From 6983727d699554ae8ddf3ed4dec0ea6d13097903 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sun, 4 Nov 2018 10:53:00 +0100 Subject: [PATCH 001/178] Reduce re-connect wait time --- src/Miningcore/Mining/BtStreamReceiver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Mining/BtStreamReceiver.cs b/src/Miningcore/Mining/BtStreamReceiver.cs index b7e757f0e..98d2002d9 100644 --- a/src/Miningcore/Mining/BtStreamReceiver.cs +++ b/src/Miningcore/Mining/BtStreamReceiver.cs @@ -120,7 +120,7 @@ private void StartMessageReceiver(ZmqPubSubEndpointConfig[] endpoints) logger.Error(() => $"{nameof(ShareReceiver)}: {ex}"); if (!cts.IsCancellationRequested) - Thread.Sleep(5000); + Thread.Sleep(1000); } } }, cts.Token); From 758518a86c54e84ee51e217cdc21b2291fdac58a Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sun, 4 Nov 2018 10:54:11 +0100 Subject: [PATCH 002/178] Mini Refactor --- src/Miningcore/Mining/BtStreamReceiver.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Miningcore/Mining/BtStreamReceiver.cs b/src/Miningcore/Mining/BtStreamReceiver.cs index 98d2002d9..a1680c6aa 100644 --- a/src/Miningcore/Mining/BtStreamReceiver.cs +++ b/src/Miningcore/Mining/BtStreamReceiver.cs @@ -155,10 +155,10 @@ private void ProcessMessage(ZMessage msg) } // convert - var json = Encoding.UTF8.GetString(data); + var content = Encoding.UTF8.GetString(data); // publish - messageBus.SendMessage(new BtStreamMessage(topic, json)); + messageBus.SendMessage(new BtStreamMessage(topic, content)); } #region API-Surface From 3536a02092d5dc50dee3dfc31d700a29308d193b Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sun, 4 Nov 2018 16:23:22 +0100 Subject: [PATCH 003/178] Eliminate Bitcoin blockreward multiplier and update actual blockreward from coinbase-tx during unlocking --- src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs | 4 ++-- src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs | 1 + src/Miningcore/Configuration/ClusterConfig.cs | 7 ------- src/Miningcore/coins.json | 5 ----- 4 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs index 31c495ed9..9365cfbb6 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs @@ -249,7 +249,7 @@ protected virtual Script GenerateScriptSigInitial() protected virtual Transaction CreateOutputTransaction() { - rewardToPool = new Money(BlockTemplate.CoinbaseValue * coin.BlockrewardMultiplier, MoneyUnit.Satoshi); + rewardToPool = new Money(BlockTemplate.CoinbaseValue, MoneyUnit.Satoshi); var tx = Transaction.Create(network); @@ -434,7 +434,7 @@ protected virtual byte[] BuildRawTransactionBuffer() protected virtual Transaction CreateMasternodeOutputTransaction() { - var blockReward = new Money(BlockTemplate.CoinbaseValue * coin.BlockrewardMultiplier, MoneyUnit.Satoshi); + var blockReward = new Money(BlockTemplate.CoinbaseValue, MoneyUnit.Satoshi); rewardToPool = new Money(BlockTemplate.CoinbaseValue, MoneyUnit.Satoshi); var tx = Transaction.Create(network); diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs index 70a42c4d9..ff4521297 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs @@ -170,6 +170,7 @@ public virtual async Task ClassifyBlocksAsync(Block[] blocks) // matured and spendable coinbase transaction block.Status = BlockStatus.Confirmed; block.ConfirmationProgress = 1; + block.Reward = transactionInfo.Amount; // update actual block-reward from coinbase-tx result.Add(block); logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index 6bf7b2052..c476be693 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -137,13 +137,6 @@ public partial class BitcoinTemplate : CoinTemplate [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool HasMasterNodes { get; set; } - /// - /// Fraction of block reward, the pool really gets to keep - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - [DefaultValue(1.0d)] - public decimal BlockrewardMultiplier { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] [DefaultValue(1.0d)] public double ShareMultiplier { get; set; } = 1.0d; diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index d2986a957..8f62169c5 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -553,7 +553,6 @@ }, "shareMultiplier": 256, "hashrateMultiplier": 4, - "blockrewardMultiplier": 100, "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", "explorerTxLink": "https://verge-blockchain.info/tx/{0}", "explorerAccountLink": "https://verge-blockchain.info/address/{0}" @@ -580,7 +579,6 @@ }, "shareMultiplier": 65536, "hashrateMultiplier": 1.5, - "blockrewardMultiplier": 100, "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", "explorerTxLink": "https://verge-blockchain.info/tx/{0}", "explorerAccountLink": "https://verge-blockchain.info/address/{0}" @@ -605,7 +603,6 @@ ] }, "hashrateMultiplier": 2.55, - "blockrewardMultiplier": 100, "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", "explorerTxLink": "https://verge-blockchain.info/tx/{0}", "explorerAccountLink": "https://verge-blockchain.info/address/{0}" @@ -629,7 +626,6 @@ } ] }, - "blockrewardMultiplier": 100, "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", "explorerTxLink": "https://verge-blockchain.info/tx/{0}", "explorerAccountLink": "https://verge-blockchain.info/address/{0}" @@ -653,7 +649,6 @@ } ] }, - "blockrewardMultiplier": 100, "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", "explorerTxLink": "https://verge-blockchain.info/tx/{0}", "explorerAccountLink": "https://verge-blockchain.info/address/{0}" From 401b03162fa831ac51a55d836a000467d1fffd1e Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sun, 4 Nov 2018 17:58:03 +0100 Subject: [PATCH 004/178] Update blockreward during unlock stage --- src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs index ff4521297..8e905c082 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs @@ -161,6 +161,7 @@ public virtual async Task ClassifyBlocksAsync(Block[] blocks) // update progress var minConfirmations = extraPoolConfig?.MinimumConfirmations ?? BitcoinConstants.CoinbaseMinConfimations; block.ConfirmationProgress = Math.Min(1.0d, (double) transactionInfo.Confirmations / minConfirmations); + block.Reward = transactionInfo.Amount; // update actual block-reward from coinbase-tx result.Add(block); messageBus.SendMessage(new BlockConfirmationProgressNotification(block.ConfirmationProgress, poolConfig.Id, block.BlockHeight, coin.Symbol)); From 8fd5daba9c6587b76ddf5357a79c471bc49d7413 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 5 Nov 2018 07:59:44 +0100 Subject: [PATCH 005/178] Explorer links --- src/Miningcore/Payments/PayoutManager.cs | 8 ++------ src/Miningcore/coins.json | 6 +++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Miningcore/Payments/PayoutManager.cs b/src/Miningcore/Payments/PayoutManager.cs index 07c0cde0a..5bbc880b0 100644 --- a/src/Miningcore/Payments/PayoutManager.cs +++ b/src/Miningcore/Payments/PayoutManager.cs @@ -143,21 +143,17 @@ private async Task UpdatePoolBalancesAsync(PoolConfig pool, IPayoutHandler handl await cf.RunTx(async (con, tx) => { - // fill block effort if empty - if (!block.Effort.HasValue) + if (!block.Effort.HasValue) // fill block effort if empty await CalculateBlockEffortAsync(pool, block, handler); - switch(block.Status) + switch (block.Status) { case BlockStatus.Confirmed: // blockchains that do not support block-reward payments via coinbase Tx // must generate balance records for all reward recipients instead var blockReward = await handler.UpdateBlockRewardBalancesAsync(con, tx, block, pool); - // update share submitter balances through configured payout scheme await scheme.UpdateBalancesAsync(con, tx, pool, handler, block, blockReward); - - // finally update block status await blockRepo.UpdateBlockAsync(con, tx, block); break; diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index 8f62169c5..d8925a8f4 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -250,9 +250,9 @@ }, "shareMultiplier": 256, "hashrateMultiplier": 4, - "explorerBlockLink": "https://bchain.info/VTC/block/$height$", - "explorerTxLink": "https://bchain.info/VTC/tx/{0}", - "explorerAccountLink": "https://bchain.info/VTC/addr/{0}" + "explorerBlockLink": "https://chainz.cryptoid.info/vtc/block.dws?$height$.htm", + "explorerTxLink": "https://chainz.cryptoid.info/vtc/tx.dws?{0}.htm", + "explorerAccountLink": "https://chainz.cryptoid.info/vtc/address.dws?{0}.htm" }, "globaltoken": { "name": "Globaltoken", From 1096ee400b542f280dcc9182cf94e91354baaaf4 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 5 Nov 2018 13:21:22 +0100 Subject: [PATCH 006/178] More logging --- .../Cryptonote/CryptonoteConstants.cs | 3 +- .../Cryptonote/CryptonotePayoutHandler.cs | 45 ++++++++++++++++--- .../DaemonResponses/GetBalanceResponse.cs | 32 +++++++++++++ 3 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 src/Miningcore/Blockchain/Cryptonote/DaemonResponses/GetBalanceResponse.cs diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteConstants.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteConstants.cs index 4670315cb..c65415459 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteConstants.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteConstants.cs @@ -79,11 +79,12 @@ public static class CryptonoteCommands public static class CryptonoteWalletCommands { - public const string GetBalance = "getbalance"; + public const string GetBalance = "get_balance"; public const string GetAddress = "getaddress"; public const string Transfer = "transfer"; public const string TransferSplit = "transfer_split"; public const string GetTransfers = "get_transfers"; public const string SplitIntegratedAddress = "split_integrated_address"; + public const string Store = "store"; } } diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs index 0b6f7f5b0..25624b320 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs @@ -44,6 +44,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using CNC = Miningcore.Blockchain.Cryptonote.CryptonoteCommands; using Miningcore.Notifications.Messages; using System.Globalization; +using Newtonsoft.Json.Linq; namespace Miningcore.Blockchain.Cryptonote { @@ -142,10 +143,33 @@ private async Task GetNetworkTypeAsync() return networkType.Value; } + private async Task EnsureBalance(decimal requiredAmount) + { + var response = await walletDaemon.ExecuteCmdSingleAsync(logger, CryptonoteWalletCommands.GetBalance); + + if (response.Error != null) + { + logger.Error(() => $"[{LogCategory}] Daemon command '{CryptonoteWalletCommands.GetBalance}' returned error: {response.Error.Message} code {response.Error.Code}"); + return false; + } + + else if (response.Response.UnlockedBalance < requiredAmount) + { + logger.Error(() => $"[{LogCategory}] Need {FormatAmount(requiredAmount)} unlocked balance, but only have {FormatAmount(response.Response.UnlockedBalance)} ({FormatAmount(response.Response.Balance)})"); + return false; + } + + return true; + } + private async Task PayoutBatch(Balance[] balances) { var coin = poolConfig.Template.As(); + // ensure there's enough balance + if (!await EnsureBalance(balances.Sum(x => x.Amount))) + return false; + // build request var request = new TransferRequest { @@ -168,7 +192,7 @@ private async Task PayoutBatch(Balance[] balances) if (request.Destinations.Length == 0) return true; - logger.Info(() => $"[{LogCategory}] Paying out {FormatAmount(balances.Sum(x => x.Amount))} to {balances.Length} addresses"); + logger.Info(() => $"[{LogCategory}] Paying out {FormatAmount(balances.Sum(x => x.Amount))} to {balances.Length} addresses:\n{string.Join("\n", balances.OrderByDescending(x => x.Amount).Select(x => $"{FormatAmount(x.Amount)} to {x.Address}"))}"); // send command var transferResponse = await walletDaemon.ExecuteCmdSingleAsync(logger, CryptonoteWalletCommands.Transfer, request); @@ -213,14 +237,17 @@ private void ExtractAddressAndPaymentId(string input, out string address, out st address = input; } - private async Task PayoutToPaymentId(Balance balance) + private async Task PayoutToPaymentId(Balance balance) { var coin = poolConfig.Template.As(); ExtractAddressAndPaymentId(balance.Address, out var address, out var paymentId); - var isIntegratedAddress = string.IsNullOrEmpty(paymentId); + // ensure there's enough balance + if (!await EnsureBalance(balance.Amount)) + return false; + // build request var request = new TransferRequest { @@ -258,7 +285,7 @@ private async Task PayoutToPaymentId(Balance balance) } } - await HandleTransferResponseAsync(result, balance); + return await HandleTransferResponseAsync(result, balance); } #region IPayoutHandler @@ -526,8 +553,14 @@ public async Task PayoutAsync(Balance[] balances) .Where(x => x.Amount >= minimumPaymentToPaymentId) .ToArray(); - foreach(var balance in paymentIdBalances) - await PayoutToPaymentId(balance); + foreach (var balance in paymentIdBalances) + { + if(!await PayoutToPaymentId(balance)) + break; + } + + // save wallet + await walletDaemon.ExecuteCmdSingleAsync(logger, CryptonoteWalletCommands.Store); } #endregion // IPayoutHandler diff --git a/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/GetBalanceResponse.cs b/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/GetBalanceResponse.cs new file mode 100644 index 000000000..ca706cf32 --- /dev/null +++ b/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/GetBalanceResponse.cs @@ -0,0 +1,32 @@ +/* +Copyright 2017 Coin Foundry (coinfoundry.org) +Authors: Oliver Weichhold (oliver@weichhold.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Cryptonote.DaemonResponses +{ + public class GetBalanceResponse + { + public decimal Balance { get; set; } + + [JsonProperty("unlocked_balance")] + public decimal UnlockedBalance { get; set; } + } +} From 0f78a964e6b59b5b7667c01312b9050cfde3f8a6 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 5 Nov 2018 13:32:58 +0100 Subject: [PATCH 007/178] Conversion fix --- .../Blockchain/Cryptonote/CryptonotePayoutHandler.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs index 25624b320..7fa75202b 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs @@ -143,7 +143,7 @@ private async Task GetNetworkTypeAsync() return networkType.Value; } - private async Task EnsureBalance(decimal requiredAmount) + private async Task EnsureBalance(decimal requiredAmount, CryptonoteCoinTemplate coin) { var response = await walletDaemon.ExecuteCmdSingleAsync(logger, CryptonoteWalletCommands.GetBalance); @@ -155,7 +155,10 @@ private async Task EnsureBalance(decimal requiredAmount) else if (response.Response.UnlockedBalance < requiredAmount) { - logger.Error(() => $"[{LogCategory}] Need {FormatAmount(requiredAmount)} unlocked balance, but only have {FormatAmount(response.Response.UnlockedBalance)} ({FormatAmount(response.Response.Balance)})"); + var unlockedBalance = Math.Floor(response.Response.UnlockedBalance / coin.SmallestUnit); + var balance = Math.Floor(response.Response.Balance / coin.SmallestUnit); + + logger.Error(() => $"[{LogCategory}] Need {FormatAmount(requiredAmount)} unlocked balance, but only have {FormatAmount(unlockedBalance)} ({FormatAmount(balance)})"); return false; } @@ -167,7 +170,7 @@ private async Task PayoutBatch(Balance[] balances) var coin = poolConfig.Template.As(); // ensure there's enough balance - if (!await EnsureBalance(balances.Sum(x => x.Amount))) + if (!await EnsureBalance(balances.Sum(x => x.Amount), coin)) return false; // build request @@ -245,7 +248,7 @@ private async Task PayoutToPaymentId(Balance balance) var isIntegratedAddress = string.IsNullOrEmpty(paymentId); // ensure there's enough balance - if (!await EnsureBalance(balance.Amount)) + if (!await EnsureBalance(balance.Amount, coin)) return false; // build request From 5fa11cdaeed309221f57fc8a48d9c454bf69f319 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 5 Nov 2018 13:37:29 +0100 Subject: [PATCH 008/178] Fixes #457 --- src/Miningcore/Persistence/Postgres/Scripts/createdb.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql index 43e71969f..7f4ced3a0 100644 --- a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql +++ b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql @@ -48,7 +48,7 @@ CREATE TABLE balances created TIMESTAMP NOT NULL, updated TIMESTAMP NOT NULL, - primary key(poolid, address, coin) + primary key(poolid, address) ); CREATE TABLE balance_changes From 6896dda9e9afeaf8a0b1eabc0ea79c1503e7382d Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 5 Nov 2018 13:43:29 +0100 Subject: [PATCH 009/178] Restore formatted JSON API responses --- src/Miningcore/Program.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Miningcore/Program.cs b/src/Miningcore/Program.cs index 52e462681..b0a5e651a 100644 --- a/src/Miningcore/Program.cs +++ b/src/Miningcore/Program.cs @@ -718,7 +718,11 @@ private static void StartApi() services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_1) - .AddControllersAsServices(); + .AddControllersAsServices() + .AddJsonOptions(options => + { + options.SerializerSettings.Formatting = Formatting.Indented; + }); // Cors services.AddCors(); From 6f9a8e36fbb2faee5dc40d4f1ed2eec59708abae Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 5 Nov 2018 13:56:12 +0100 Subject: [PATCH 010/178] Fixes #428 --- src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs | 1 + .../Blockchain/Bitcoin/BitcoinJobManagerBase.cs | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs index a06c96d32..f2c7ceea0 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs @@ -163,6 +163,7 @@ public static class BitcoinCommands public const string SendMany = "sendmany"; public const string WalletPassphrase = "walletpassphrase"; public const string WalletLock = "walletlock"; + public const string GetNetworkHashps = "getnetworkhashps"; // Legacy commands public const string GetInfo = "getinfo"; diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index 4de682009..707f11d48 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -254,7 +254,8 @@ private async Task UpdateNetworkStatsAsync() { var results = await daemon.ExecuteBatchAnyAsync(logger, new DaemonCmd(BitcoinCommands.GetMiningInfo), - new DaemonCmd(BitcoinCommands.GetNetworkInfo) + new DaemonCmd(BitcoinCommands.GetNetworkInfo), + new DaemonCmd(BitcoinCommands.GetNetworkHashps) ); if (results.Any(x => x.Error != null)) @@ -267,8 +268,12 @@ private async Task UpdateNetworkStatsAsync() var miningInfoResponse = results[0].Response.ToObject(); var networkInfoResponse = results[1].Response.ToObject(); + var networkHashRate = results[2].Response.ToObject(); + + BlockchainStats.NetworkHashrate = miningInfoResponse.NetworkHashps > 0 ? + miningInfoResponse.NetworkHashps : + results[2].Error != null ? networkHashRate.Value() : 0; - BlockchainStats.NetworkHashrate = miningInfoResponse.NetworkHashps; BlockchainStats.ConnectedPeers = networkInfoResponse.Connections; } From ec6d50a3fbe8905bdaae729726fcc9149be8810d Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 5 Nov 2018 13:59:54 +0100 Subject: [PATCH 011/178] WIP --- src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index 707f11d48..88f2676ad 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -270,9 +270,9 @@ private async Task UpdateNetworkStatsAsync() var networkInfoResponse = results[1].Response.ToObject(); var networkHashRate = results[2].Response.ToObject(); - BlockchainStats.NetworkHashrate = miningInfoResponse.NetworkHashps > 0 ? - miningInfoResponse.NetworkHashps : - results[2].Error != null ? networkHashRate.Value() : 0; + BlockchainStats.NetworkHashrate = results[2].Error != null ? + networkHashRate.Value() : + miningInfoResponse.NetworkHashps; BlockchainStats.ConnectedPeers = networkInfoResponse.Connections; } From 11c607bd7cd78ed7c700b52377a84e34688dde03 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 5 Nov 2018 18:22:17 +0100 Subject: [PATCH 012/178] Log tx key --- .../Blockchain/Cryptonote/CryptonotePayoutHandler.cs | 2 +- .../Cryptonote/DaemonRequests/TransferRequest.cs | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs index 7fa75202b..794ac0cfe 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs @@ -89,7 +89,7 @@ private async Task HandleTransferResponseAsync(DaemonResponse $"[{LogCategory}] Payout transaction id: {txHash}, TxFee was {FormatAmount(txFee)}"); + logger.Info(() => $"[{LogCategory}] Payout transaction id: {txHash}, TxFee {FormatAmount(txFee)}, TxKey {response.Response.TxKey}"); await PersistPaymentsAsync(balances, txHash); NotifyPayoutSuccess(poolConfig.Id, balances, new[] { txHash }, txFee); diff --git a/src/Miningcore/Blockchain/Cryptonote/DaemonRequests/TransferRequest.cs b/src/Miningcore/Blockchain/Cryptonote/DaemonRequests/TransferRequest.cs index c843a5667..bc2c36997 100644 --- a/src/Miningcore/Blockchain/Cryptonote/DaemonRequests/TransferRequest.cs +++ b/src/Miningcore/Blockchain/Cryptonote/DaemonRequests/TransferRequest.cs @@ -37,6 +37,17 @@ public class TransferRequest /// public uint Mixin { get; set; } + /// + /// Set a priority for the transaction. Accepted Values are: 0-3 for: default, unimportant, normal, elevated, priority + /// + public uint Priority { get; set; } + + /// + /// Number of outputs to mix in the transaction (this output + N decoys from the blockchain) + /// + [JsonProperty("ring_size")] + public uint RingSize { get; set; } = 7; + /// /// (Optional) Random 32-byte/64-character hex string to identify a transaction /// From db7c68fdea25de523456b1efebdd416f645764ca Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 5 Nov 2018 18:29:17 +0100 Subject: [PATCH 013/178] Version-Rolling logging --- src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs index 936831b72..0a88cc6a2 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs @@ -305,6 +305,8 @@ private void ConfigureVersionRolling(StratumClient client, BitcoinWorkerContext // enabled result[BitcoinStratumExtensions.VersionRolling] = true; result[BitcoinStratumExtensions.VersionRollingMask] = context.VersionRollingMask.Value.ToStringHex8(); + + logger.Info(() => $"[{client.ConnectionId}] Using version-rolling mask {result[BitcoinStratumExtensions.VersionRollingMask]}"); } private void ConfigureMinimumDiff(StratumClient client, BitcoinWorkerContext context, From 8970205a16f5d85af07f5ba27b6ebe475b265f7f Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 6 Nov 2018 12:57:54 +0100 Subject: [PATCH 014/178] Revert "Fixes #428" --- src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs | 1 - .../Blockchain/Bitcoin/BitcoinJobManagerBase.cs | 9 ++------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs index f2c7ceea0..a06c96d32 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs @@ -163,7 +163,6 @@ public static class BitcoinCommands public const string SendMany = "sendmany"; public const string WalletPassphrase = "walletpassphrase"; public const string WalletLock = "walletlock"; - public const string GetNetworkHashps = "getnetworkhashps"; // Legacy commands public const string GetInfo = "getinfo"; diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index 88f2676ad..55646db27 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -254,8 +254,7 @@ private async Task UpdateNetworkStatsAsync() { var results = await daemon.ExecuteBatchAnyAsync(logger, new DaemonCmd(BitcoinCommands.GetMiningInfo), - new DaemonCmd(BitcoinCommands.GetNetworkInfo), - new DaemonCmd(BitcoinCommands.GetNetworkHashps) + new DaemonCmd(BitcoinCommands.GetNetworkInfo) ); if (results.Any(x => x.Error != null)) @@ -268,12 +267,8 @@ private async Task UpdateNetworkStatsAsync() var miningInfoResponse = results[0].Response.ToObject(); var networkInfoResponse = results[1].Response.ToObject(); - var networkHashRate = results[2].Response.ToObject(); - - BlockchainStats.NetworkHashrate = results[2].Error != null ? - networkHashRate.Value() : - miningInfoResponse.NetworkHashps; + BlockchainStats.NetworkHashrate = miningInfoResponse.NetworkHashps; BlockchainStats.ConnectedPeers = networkInfoResponse.Connections; } From 9352f4dffbb4dbc652cd037181edbe373ecf8d2d Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 6 Nov 2018 15:30:55 +0100 Subject: [PATCH 015/178] Payout by ordered balance --- src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs index 794ac0cfe..698098ae0 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs @@ -526,6 +526,7 @@ public async Task PayoutAsync(Balance[] balances) return !hasPaymentId && !isIntegratedAddress; }) + .OrderByDescending(x=> x.Amount) .ToArray(); if (simpleBalances.Length > 0) From ee28eb6ba99b570d5add81e474e521950f436aa7 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 6 Nov 2018 19:05:23 +0100 Subject: [PATCH 016/178] sv/gamma fix --- .../Blockchain/Cryptonote/CryptonotePayoutHandler.cs | 2 +- .../Cryptonote/DaemonRequests/TransferRequest.cs | 6 ++++++ .../Cryptonote/DaemonResponses/TransferResponse.cs | 12 ++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs index 698098ae0..11e4722cc 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs @@ -534,7 +534,7 @@ public async Task PayoutAsync(Balance[] balances) await PayoutBatch(simpleBalances); #else { - var maxBatchSize = 28; + var maxBatchSize = 15; // going over 15 yields "sv/gamma are too large" var pageSize = maxBatchSize; var pageCount = (int) Math.Ceiling((double) simpleBalances.Length / pageSize); diff --git a/src/Miningcore/Blockchain/Cryptonote/DaemonRequests/TransferRequest.cs b/src/Miningcore/Blockchain/Cryptonote/DaemonRequests/TransferRequest.cs index bc2c36997..db702df45 100644 --- a/src/Miningcore/Blockchain/Cryptonote/DaemonRequests/TransferRequest.cs +++ b/src/Miningcore/Blockchain/Cryptonote/DaemonRequests/TransferRequest.cs @@ -60,6 +60,12 @@ public class TransferRequest [JsonProperty("get_tx_key")] public bool GetTxKey { get; set; } + /// + /// (Optional) Return the transaction key after sending + /// + [JsonProperty("get_tx_hex")] + public bool GetTxHex { get; set; } + /// /// Number of blocks before the monero can be spent (0 to not add a lock) /// diff --git a/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/TransferResponse.cs b/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/TransferResponse.cs index 47136ddf2..a7470ddca 100644 --- a/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/TransferResponse.cs +++ b/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/TransferResponse.cs @@ -41,6 +41,18 @@ public class TransferResponse [JsonProperty("tx_hash")] public string TxHash { get; set; } + /// + /// Raw transaction represented as hex string, if get_tx_hex is true. + /// + [JsonProperty("tx_blob")] + public string TxBlob { get; set; } + + /// + /// (Optional) If true, the newly created transaction will not be relayed to the monero network + /// + [JsonProperty("do_not_relay")] + public string DoNotRelay { get; set; } + public string Status { get; set; } } } From a8c961f415449ea40b1122a40adf9b45f5b011bb Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 6 Nov 2018 19:35:35 +0100 Subject: [PATCH 017/178] Always set blockreward to zero if orphaned --- src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs index 8e905c082..88cc335c5 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs @@ -137,6 +137,7 @@ public virtual async Task ClassifyBlocksAsync(Block[] blocks) if (cmdResult.Error.Code == -5) { block.Status = BlockStatus.Orphaned; + block.Reward = 0; result.Add(block); } @@ -150,6 +151,7 @@ public virtual async Task ClassifyBlocksAsync(Block[] blocks) else if (transactionInfo?.Details == null || transactionInfo.Details.Length == 0) { block.Status = BlockStatus.Orphaned; + block.Reward = 0; result.Add(block); } From 12f0b75485148bbeea7c36466e156132b185cbec Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 6 Nov 2018 19:38:06 +0100 Subject: [PATCH 018/178] Do not set blockreward until confirmed --- src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs index 9365cfbb6..07a8ed16d 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs @@ -361,7 +361,6 @@ protected virtual (Share Share, string BlockHex) ProcessShareInternal( if (isBlockCandidate) { result.IsBlockCandidate = true; - result.BlockReward = rewardToPool.ToDecimal(MoneyUnit.BTC); Span blockHash = stackalloc byte[32]; blockHasher.Digest(headerBytes, blockHash, nTime); From 993fc8c52d1a0c89f9994f25878ec259d759def3 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 6 Nov 2018 19:48:23 +0100 Subject: [PATCH 019/178] Eliminate BlockrewardMultiplier --- .../Equihash/Custom/BitcoinGold/BitcoinGoldJob.cs | 2 +- src/Miningcore/Configuration/ClusterConfig.cs | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Miningcore/Blockchain/Equihash/Custom/BitcoinGold/BitcoinGoldJob.cs b/src/Miningcore/Blockchain/Equihash/Custom/BitcoinGold/BitcoinGoldJob.cs index 181e92d29..d9b0d2284 100644 --- a/src/Miningcore/Blockchain/Equihash/Custom/BitcoinGold/BitcoinGoldJob.cs +++ b/src/Miningcore/Blockchain/Equihash/Custom/BitcoinGold/BitcoinGoldJob.cs @@ -45,7 +45,7 @@ public class BitcoinGoldJob : EquihashJob protected override Transaction CreateOutputTransaction() { - rewardToPool = new Money(BlockTemplate.CoinbaseValue * coin.BlockrewardMultiplier, MoneyUnit.Satoshi); + rewardToPool = new Money(BlockTemplate.CoinbaseValue, MoneyUnit.Satoshi); var tx = Transaction.Create(network); diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index c476be693..e74f893a7 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -222,13 +222,6 @@ public partial class EquihashNetworkParams /// Force use of BitcoinPayoutHandler instead of EquihashPayoutHandler /// public bool UseBitcoinPayoutHandler { get; set; } - - /// - /// Fraction of block reward, the pool really gets to keep - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - [DefaultValue(1.0d)] - public decimal BlockrewardMultiplier { get; set; } } public enum CryptonoteSubfamily From efa2067a14c2baf79ab48278897c1fe9187028f7 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 6 Nov 2018 20:01:55 +0100 Subject: [PATCH 020/178] Log current balance --- .../Blockchain/Cryptonote/CryptonotePayoutHandler.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs index 11e4722cc..603d57370 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs @@ -153,15 +153,16 @@ private async Task EnsureBalance(decimal requiredAmount, CryptonoteCoinTem return false; } - else if (response.Response.UnlockedBalance < requiredAmount) - { - var unlockedBalance = Math.Floor(response.Response.UnlockedBalance / coin.SmallestUnit); - var balance = Math.Floor(response.Response.Balance / coin.SmallestUnit); + var unlockedBalance = Math.Floor(response.Response.UnlockedBalance / coin.SmallestUnit); + var balance = Math.Floor(response.Response.Balance / coin.SmallestUnit); + if (response.Response.UnlockedBalance < requiredAmount) + { logger.Error(() => $"[{LogCategory}] Need {FormatAmount(requiredAmount)} unlocked balance, but only have {FormatAmount(unlockedBalance)} ({FormatAmount(balance)})"); return false; } + logger.Error(() => $"[{LogCategory}] Current balance is {FormatAmount(unlockedBalance)}"); return true; } From ea3a171fb52877c451082ce86df99ca8870af97e Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 6 Nov 2018 21:34:05 +0100 Subject: [PATCH 021/178] Alternative way to detect network hashrate for bitcoin --- src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs | 1 + src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs index a06c96d32..c7c553306 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs @@ -152,6 +152,7 @@ public static class BitcoinCommands public const string ListUnspent = "listunspent"; public const string GetNetworkInfo = "getnetworkinfo"; public const string GetMiningInfo = "getmininginfo"; + public const string GetNetworkHashPS = "getnetworkhashps"; public const string GetPeerInfo = "getpeerinfo"; public const string ValidateAddress = "validateaddress"; public const string GetBlockTemplate = "getblocktemplate"; diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index 55646db27..b9dd7ae78 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -254,7 +254,8 @@ private async Task UpdateNetworkStatsAsync() { var results = await daemon.ExecuteBatchAnyAsync(logger, new DaemonCmd(BitcoinCommands.GetMiningInfo), - new DaemonCmd(BitcoinCommands.GetNetworkInfo) + new DaemonCmd(BitcoinCommands.GetNetworkInfo), + new DaemonCmd(BitcoinCommands.GetNetworkHashPS) ); if (results.Any(x => x.Error != null)) @@ -270,6 +271,9 @@ private async Task UpdateNetworkStatsAsync() BlockchainStats.NetworkHashrate = miningInfoResponse.NetworkHashps; BlockchainStats.ConnectedPeers = networkInfoResponse.Connections; + + if (BlockchainStats.NetworkHashrate == 0 && results[2].Error == null) + BlockchainStats.NetworkHashrate = results[2].Response.Value(); } catch(Exception e) From 43840d1c63729198241fa12783d9039be774e9b2 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 6 Nov 2018 22:05:46 +0100 Subject: [PATCH 022/178] Fix tests --- src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs | 1 - src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs b/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs index 98cfac226..aa882e358 100644 --- a/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs +++ b/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs @@ -63,7 +63,6 @@ public void BitcoinJob_Should_Accept_Valid_Share() Assert.Equal(share.BlockHash, "601ed85039804bcecbbdb53e0ca358aeb8dabef2366fb64c216aac3aba02b716"); Assert.Equal(blockHex, "00000020bb76da6422b707a90831c421798123293bc5fd377bbeb5198557090900000000fd5418fe788ef961678e4bacdd1fe3903185b9ec63865bb3d2d279bb0eb48c0bf286ef59ffff7f206aae848d0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff295e0c0b2f454231362f414431322f04f286ef590001000058010000000c2f4d696e696e67436f72652f000000000100f2052a010000001976a9142ebb5cccf9a6bb927661d2953655c43c04accc3788ac00000000"); Assert.Equal(share.BlockHeight, 14); - Assert.Equal(share.BlockReward, 50); Assert.Equal(share.Difficulty, 0.5); } diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index b9dd7ae78..2b1b6b1a0 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -272,6 +272,7 @@ private async Task UpdateNetworkStatsAsync() BlockchainStats.NetworkHashrate = miningInfoResponse.NetworkHashps; BlockchainStats.ConnectedPeers = networkInfoResponse.Connections; + // Fall back to alternative RPC if coin does not report Network HPS (Digibyte) if (BlockchainStats.NetworkHashrate == 0 && results[2].Error == null) BlockchainStats.NetworkHashrate = results[2].Response.Value(); } From cc34e91292aacb0efd0dca622654bcbb769c715e Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 6 Nov 2018 23:26:51 +0100 Subject: [PATCH 023/178] Dispose SslStream --- src/Miningcore/Stratum/StratumClient.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Miningcore/Stratum/StratumClient.cs b/src/Miningcore/Stratum/StratumClient.cs index 517dc0898..13fd109a2 100644 --- a/src/Miningcore/Stratum/StratumClient.cs +++ b/src/Miningcore/Stratum/StratumClient.cs @@ -120,7 +120,7 @@ public void Run(Socket socket, // create stream networkStream = new NetworkStream(socket, true); - using (new CompositeDisposable(networkStream, cts)) + using (var disposables = new CompositeDisposable(networkStream, cts)) { // TLS handshake if (poolEndpoint.PoolEndpoint.Tls) @@ -129,6 +129,8 @@ public void Run(Socket socket, await sslStream.AuthenticateAsServerAsync(tlsCert, false, SslProtocols.Tls11 | SslProtocols.Tls12, false); networkStream = sslStream; + disposables.Add(sslStream); + logger.Info(() => $"[{ConnectionId}] {sslStream.SslProtocol.ToString().ToUpper()}-{sslStream.CipherAlgorithm.ToString().ToUpper()} Connection from {RemoteEndpoint.Address}:{RemoteEndpoint.Port} accepted on port {poolEndpoint.IPEndPoint.Port}"); } From 5033b337fe3a790d4378c321c87886e971cea13f Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 6 Nov 2018 23:29:05 +0100 Subject: [PATCH 024/178] Mini-refactor --- src/Miningcore/Stratum/StratumClient.cs | 18 +++++++++--------- src/Miningcore/Stratum/StratumServer.cs | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Miningcore/Stratum/StratumClient.cs b/src/Miningcore/Stratum/StratumClient.cs index 13fd109a2..d34d1a5ae 100644 --- a/src/Miningcore/Stratum/StratumClient.cs +++ b/src/Miningcore/Stratum/StratumClient.cs @@ -98,16 +98,16 @@ public StratumClient() #region API-Surface public void Run(Socket socket, - (IPEndPoint IPEndPoint, PoolEndpoint PoolEndpoint) poolEndpoint, - X509Certificate2 tlsCert, + (IPEndPoint IPEndPoint, PoolEndpoint PoolEndpoint) endpoint, + X509Certificate2 cert, Func onRequestAsync, Action onCompleted, Action onError) { - PoolEndpoint = poolEndpoint.IPEndPoint; + PoolEndpoint = endpoint.IPEndPoint; RemoteEndpoint = (IPEndPoint)socket.RemoteEndPoint; - expectingProxyHeader = poolEndpoint.PoolEndpoint.TcpProxyProtocol?.Enable == true; + expectingProxyHeader = endpoint.PoolEndpoint.TcpProxyProtocol?.Enable == true; Task.Run(async () => { @@ -123,25 +123,25 @@ public void Run(Socket socket, using (var disposables = new CompositeDisposable(networkStream, cts)) { // TLS handshake - if (poolEndpoint.PoolEndpoint.Tls) + if (endpoint.PoolEndpoint.Tls) { var sslStream = new SslStream(networkStream, false); - await sslStream.AuthenticateAsServerAsync(tlsCert, false, SslProtocols.Tls11 | SslProtocols.Tls12, false); + await sslStream.AuthenticateAsServerAsync(cert, false, SslProtocols.Tls11 | SslProtocols.Tls12, false); networkStream = sslStream; disposables.Add(sslStream); - logger.Info(() => $"[{ConnectionId}] {sslStream.SslProtocol.ToString().ToUpper()}-{sslStream.CipherAlgorithm.ToString().ToUpper()} Connection from {RemoteEndpoint.Address}:{RemoteEndpoint.Port} accepted on port {poolEndpoint.IPEndPoint.Port}"); + logger.Info(() => $"[{ConnectionId}] {sslStream.SslProtocol.ToString().ToUpper()}-{sslStream.CipherAlgorithm.ToString().ToUpper()} Connection from {RemoteEndpoint.Address}:{RemoteEndpoint.Port} accepted on port {endpoint.IPEndPoint.Port}"); } else - logger.Info(() => $"[{ConnectionId}] Connection from {RemoteEndpoint.Address}:{RemoteEndpoint.Port} accepted on port {poolEndpoint.IPEndPoint.Port}"); + logger.Info(() => $"[{ConnectionId}] Connection from {RemoteEndpoint.Address}:{RemoteEndpoint.Port} accepted on port {endpoint.IPEndPoint.Port}"); // Async I/O loop(s) var tasks = new[] { FillReceivePipeAsync(), - ProcessReceivePipeAsync(poolEndpoint.PoolEndpoint.TcpProxyProtocol, onRequestAsync), + ProcessReceivePipeAsync(endpoint.PoolEndpoint.TcpProxyProtocol, onRequestAsync), ProcessSendQueueAsync() }; diff --git a/src/Miningcore/Stratum/StratumServer.cs b/src/Miningcore/Stratum/StratumServer.cs index 9a834eefe..3c724a796 100644 --- a/src/Miningcore/Stratum/StratumServer.cs +++ b/src/Miningcore/Stratum/StratumServer.cs @@ -177,12 +177,12 @@ private void AcceptConnection(Socket socket, (IPEndPoint IPEndPoint, PoolEndpoin } // TLS cert loading - X509Certificate2 tlsCert = null; + X509Certificate2 cert = null; if (port.PoolEndpoint.Tls) { - if (!certs.TryGetValue(port.PoolEndpoint.TlsPfxFile, out tlsCert)) - tlsCert = AddCert(port); + if (!certs.TryGetValue(port.PoolEndpoint.TlsPfxFile, out cert)) + cert = AddCert(port); } // setup client @@ -190,7 +190,7 @@ private void AcceptConnection(Socket socket, (IPEndPoint IPEndPoint, PoolEndpoin RegisterClient(client, connectionId); OnConnect(client, port.IPEndPoint); - client.Run(socket, port, tlsCert, OnRequestAsync, OnClientComplete, OnClientError); + client.Run(socket, port, cert, OnRequestAsync, OnClientComplete, OnClientError); } public void StopListeners() From 4d7228424389cfb785babdfde3ef889602be7ee9 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 6 Nov 2018 23:56:01 +0100 Subject: [PATCH 025/178] Log bitcoin family shares with actual stratum diff --- .../Blockchain/Bitcoin/BitcoinPool.cs | 30 ++++++++++++------- src/Miningcore/Mining/ShareReceiver.cs | 6 +++- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs index 0a88cc6a2..ce673c407 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs @@ -61,16 +61,7 @@ public BitcoinPool(IComponentContext ctx, protected object currentJobParams; protected BitcoinJobManager manager; - - public override double HashrateFromShares(double shares, double interval) - { - var multiplier = BitcoinConstants.Pow2x32; - var result = shares * multiplier / interval; - - result *= poolConfig.Template.As().HashrateMultiplier; - - return result; - } + private BitcoinTemplate coin; protected virtual async Task OnSubscribeAsync(StratumClient client, Timestamped tsRequest) { @@ -206,7 +197,7 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped $"[{client.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty, 3)}"); + logger.Info(() => $"[{client.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty * coin.ShareMultiplier, 3)}"); // update pool stats if (share.IsBlockCandidate) @@ -375,8 +366,25 @@ protected virtual async Task OnNewJobAsync(object jobParams) } } + public override double HashrateFromShares(double shares, double interval) + { + var multiplier = BitcoinConstants.Pow2x32; + var result = shares * multiplier / interval; + + result *= coin.HashrateMultiplier; + + return result; + } + #region Overrides + public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfig) + { + coin = poolConfig.Template.As(); + + base.Configure(poolConfig, clusterConfig); + } + protected override async Task SetupJobManager(CancellationToken ct) { manager = ctx.Resolve( diff --git a/src/Miningcore/Mining/ShareReceiver.cs b/src/Miningcore/Mining/ShareReceiver.cs index 5235d5f5c..d78485660 100644 --- a/src/Miningcore/Mining/ShareReceiver.cs +++ b/src/Miningcore/Mining/ShareReceiver.cs @@ -250,7 +250,11 @@ private void ProcessMessage(string url, ZMessage msg) if (pools.TryGetValue(topic, out var poolContext)) { var pool = poolContext.Pool; - poolContext.Logger.Info(() => $"External {(!string.IsNullOrEmpty(share.Source) ? $"[{share.Source.ToUpper()}] " : string.Empty)}share accepted: D={Math.Round(share.Difficulty, 3)}"); + + var shareMultiplier = pool.Config.Template.Family == CoinFamily.Bitcoin ? + pool.Config.Template.As().ShareMultiplier : 1; + + poolContext.Logger.Info(() => $"External {(!string.IsNullOrEmpty(share.Source) ? $"[{share.Source.ToUpper()}] " : string.Empty)}share accepted: D={Math.Round(share.Difficulty * shareMultiplier, 3)}"); if (pool.NetworkStats != null) { From 86c820ac4202d99f094843ad9b7448af890b4d29 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 7 Nov 2018 08:42:02 +0100 Subject: [PATCH 026/178] Per-relay reconnect on timeout --- src/Miningcore/Mining/ShareReceiver.cs | 66 +++++++++++++++----------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/src/Miningcore/Mining/ShareReceiver.cs b/src/Miningcore/Mining/ShareReceiver.cs index d78485660..a24d671f3 100644 --- a/src/Miningcore/Mining/ShareReceiver.cs +++ b/src/Miningcore/Mining/ShareReceiver.cs @@ -74,33 +74,25 @@ private void StartMessageReceiver() var timeout = TimeSpan.FromMilliseconds(1000); var reconnectTimeout = TimeSpan.FromSeconds(60); + var relays = clusterConfig.ShareRelays + .DistinctBy(x => $"{x.Url}:{x.SharedEncryptionKey}") + .ToArray(); + while (!cts.IsCancellationRequested) { - var lastMessageReceived = clock.Now; + // track last message received per-endpoint + var lastMessageReceived = relays.Select(_ => clock.Now).ToArray(); ; try { // setup sockets - var sockets = clusterConfig.ShareRelays - .DistinctBy(x => $"{x.Url}:{x.SharedEncryptionKey}") - .Select(relay => - { - var subSocket = new ZSocket(ZSocketType.SUB); - subSocket.SetupCurveTlsClient(relay.SharedEncryptionKey, logger); - subSocket.Connect(relay.Url); - subSocket.SubscribeAll(); - - if (subSocket.CurveServerKey != null) - logger.Info($"Monitoring external stratum {relay.Url} using Curve public-key {subSocket.CurveServerKey.ToHexString()}"); - else - logger.Info($"Monitoring external stratum {relay.Url}"); - - return subSocket; - }).ToArray(); + var sockets = relays + .Select(SetupSubSocket) + .ToArray(); using (new CompositeDisposable(sockets)) { - var urls = clusterConfig.ShareRelays.Select(x => x.Url).ToArray(); + var urls = relays.Select(x => x.Url).ToArray(); var pollItems = sockets.Select(_ => ZPollItem.CreateReceiver()).ToArray(); while (!cts.IsCancellationRequested) @@ -113,24 +105,27 @@ private void StartMessageReceiver() if (msg != null) { - lastMessageReceived = clock.Now; + lastMessageReceived[i] = clock.Now; queue.Post((urls[i], msg)); } + + else if (clock.Now - lastMessageReceived[i] > reconnectTimeout) + { + // re-create socket + sockets[i].Dispose(); + sockets[i] = SetupSubSocket(relays[i]); + + // reset clock + lastMessageReceived[i] = clock.Now; + + logger.Info(() => $"Receive timeout of {reconnectTimeout.TotalSeconds} seconds exceeded. Re-connecting to {urls[i]} ..."); + } } if (error != null) logger.Error(() => $"{nameof(ShareReceiver)}: {error.Name} [{error.Name}] during receive"); } - - else - { - if (clock.Now - lastMessageReceived > reconnectTimeout) - { - logger.Info(() => $"Receive timeout of {reconnectTimeout.TotalSeconds} seconds exceeded. Re-connecting ..."); - break; - } - } } } } @@ -146,6 +141,21 @@ private void StartMessageReceiver() }, cts.Token); } + private static ZSocket SetupSubSocket(ShareRelayEndpointConfig relay) + { + var subSocket = new ZSocket(ZSocketType.SUB); + subSocket.SetupCurveTlsClient(relay.SharedEncryptionKey, logger); + subSocket.Connect(relay.Url); + subSocket.SubscribeAll(); + + if (subSocket.CurveServerKey != null) + logger.Info($"Monitoring external stratum {relay.Url} using Curve public-key {subSocket.CurveServerKey.ToHexString()}"); + else + logger.Info($"Monitoring external stratum {relay.Url}"); + + return subSocket; + } + private void StartMessageProcessors() { for (var i = 0; i < Environment.ProcessorCount; i++) From 7363f090a0b06aeb7a03b70815639412ccac1553 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 7 Nov 2018 08:44:28 +0100 Subject: [PATCH 027/178] Cleanup --- src/Miningcore/Mining/ShareReceiver.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Miningcore/Mining/ShareReceiver.cs b/src/Miningcore/Mining/ShareReceiver.cs index a24d671f3..6fc4daf65 100644 --- a/src/Miningcore/Mining/ShareReceiver.cs +++ b/src/Miningcore/Mining/ShareReceiver.cs @@ -80,19 +80,16 @@ private void StartMessageReceiver() while (!cts.IsCancellationRequested) { - // track last message received per-endpoint - var lastMessageReceived = relays.Select(_ => clock.Now).ToArray(); ; + // track last message received per endpoint + var lastMessageReceived = relays.Select(_ => clock.Now).ToArray(); try { // setup sockets - var sockets = relays - .Select(SetupSubSocket) - .ToArray(); + var sockets = relays.Select(SetupSubSocket).ToArray(); using (new CompositeDisposable(sockets)) { - var urls = relays.Select(x => x.Url).ToArray(); var pollItems = sockets.Select(_ => ZPollItem.CreateReceiver()).ToArray(); while (!cts.IsCancellationRequested) @@ -107,7 +104,7 @@ private void StartMessageReceiver() { lastMessageReceived[i] = clock.Now; - queue.Post((urls[i], msg)); + queue.Post((relays[i].Url, msg)); } else if (clock.Now - lastMessageReceived[i] > reconnectTimeout) @@ -119,7 +116,7 @@ private void StartMessageReceiver() // reset clock lastMessageReceived[i] = clock.Now; - logger.Info(() => $"Receive timeout of {reconnectTimeout.TotalSeconds} seconds exceeded. Re-connecting to {urls[i]} ..."); + logger.Info(() => $"Receive timeout of {reconnectTimeout.TotalSeconds} seconds exceeded. Re-connecting to {relays[i].Url} ..."); } } From 8fa63ffe240bef2a1b9e3a9c91b13844014c90dc Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 7 Nov 2018 10:59:11 +0100 Subject: [PATCH 028/178] sslstream disposing was still not 100% ensured --- src/Miningcore/Stratum/StratumClient.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Miningcore/Stratum/StratumClient.cs b/src/Miningcore/Stratum/StratumClient.cs index d34d1a5ae..559329f96 100644 --- a/src/Miningcore/Stratum/StratumClient.cs +++ b/src/Miningcore/Stratum/StratumClient.cs @@ -122,14 +122,14 @@ public void Run(Socket socket, using (var disposables = new CompositeDisposable(networkStream, cts)) { - // TLS handshake if (endpoint.PoolEndpoint.Tls) { var sslStream = new SslStream(networkStream, false); + disposables.Add(sslStream); + + // TLS handshake await sslStream.AuthenticateAsServerAsync(cert, false, SslProtocols.Tls11 | SslProtocols.Tls12, false); - networkStream = sslStream; - disposables.Add(sslStream); logger.Info(() => $"[{ConnectionId}] {sslStream.SslProtocol.ToString().ToUpper()}-{sslStream.CipherAlgorithm.ToString().ToUpper()} Connection from {RemoteEndpoint.Address}:{RemoteEndpoint.Port} accepted on port {endpoint.IPEndPoint.Port}"); } From 4ad951dff187106f33684b6c7d1265044e0db4b7 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 7 Nov 2018 15:07:09 +0100 Subject: [PATCH 029/178] Don't check notification enable status on publisher side! --- src/Miningcore/Notifications/NotificationService.cs | 12 ------------ src/Miningcore/Payments/PayoutHandlerBase.cs | 12 ++++-------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/Miningcore/Notifications/NotificationService.cs b/src/Miningcore/Notifications/NotificationService.cs index ddc14806c..1bbacb60c 100644 --- a/src/Miningcore/Notifications/NotificationService.cs +++ b/src/Miningcore/Notifications/NotificationService.cs @@ -116,15 +116,8 @@ public NotificationService( //private readonly string adminPhone; private readonly BlockingCollection queue; - - private readonly Regex regexStripHtml = new Regex(@"<[^>]*>", RegexOptions.Compiled); private IDisposable queueSub; - private readonly HttpClient httpClient = new HttpClient(new SocketsHttpHandler - { - AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip - }); - enum NotificationCategory { Admin, @@ -168,11 +161,6 @@ private async Task SendNotificationAsync(QueuedNotification notification) break; case NotificationCategory.PaymentSuccess: - if (clusterConfig.Notifications?.Admin?.Enabled == true && - clusterConfig.Notifications?.Admin?.NotifyPaymentSuccess == true) - await SendEmailAsync(adminEmail, notification.Subject, notification.Msg); - break; - case NotificationCategory.PaymentFailure: if (clusterConfig.Notifications?.Admin?.Enabled == true && clusterConfig.Notifications?.Admin?.NotifyPaymentSuccess == true) diff --git a/src/Miningcore/Payments/PayoutHandlerBase.cs b/src/Miningcore/Payments/PayoutHandlerBase.cs index d78d6aff4..820dbe40e 100644 --- a/src/Miningcore/Payments/PayoutHandlerBase.cs +++ b/src/Miningcore/Payments/PayoutHandlerBase.cs @@ -184,15 +184,11 @@ protected virtual void NotifyPayoutSuccess(string poolId, Balance[] balances, st var coin = poolConfig.Template.As(); // admin notifications - if (clusterConfig.Notifications?.Admin?.Enabled == true && - clusterConfig.Notifications?.Admin?.NotifyPaymentSuccess == true) - { - var explorerLinks = !string.IsNullOrEmpty(coin.ExplorerTxLink) ? - txHashes.Select(x => string.Format(coin.ExplorerTxLink, x)).ToArray() : - new string[0]; + var explorerLinks = !string.IsNullOrEmpty(coin.ExplorerTxLink) ? + txHashes.Select(x => string.Format(coin.ExplorerTxLink, x)).ToArray() : + new string[0]; - messageBus.SendMessage(new PaymentNotification(poolId, null, balances.Sum(x => x.Amount), coin.Symbol, balances.Length, txHashes, explorerLinks, txFee)); - } + messageBus.SendMessage(new PaymentNotification(poolId, null, balances.Sum(x => x.Amount), coin.Symbol, balances.Length, txHashes, explorerLinks, txFee)); } protected virtual void NotifyPayoutFailure(string poolId, Balance[] balances, string error, Exception ex) From 73680f111f11392716a94357a630233593fdcd5d Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 7 Nov 2018 19:58:25 +0100 Subject: [PATCH 030/178] More compact implementation of BtStreamReceiver receiver logic including re-connect on receive-timeout. --- src/Miningcore/Mining/BtStreamReceiver.cs | 62 +++++++++++++---------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/src/Miningcore/Mining/BtStreamReceiver.cs b/src/Miningcore/Mining/BtStreamReceiver.cs index a1680c6aa..1a3d98b66 100644 --- a/src/Miningcore/Mining/BtStreamReceiver.cs +++ b/src/Miningcore/Mining/BtStreamReceiver.cs @@ -52,32 +52,22 @@ private void StartMessageReceiver(ZmqPubSubEndpointConfig[] endpoints) var timeout = TimeSpan.FromMilliseconds(1000); var reconnectTimeout = TimeSpan.FromSeconds(300); + var relays = endpoints + .DistinctBy(x => $"{x.Url}:{x.SharedEncryptionKey}") + .ToArray(); + while (!cts.IsCancellationRequested) { - var lastMessageReceived = clock.Now; + // track last message received per endpoint + var lastMessageReceived = relays.Select(_ => clock.Now).ToArray(); try { // setup sockets - var sockets = endpoints - .Select(endpoint => - { - var subSocket = new ZSocket(ZSocketType.SUB); - subSocket.SetupCurveTlsClient(endpoint.SharedEncryptionKey, logger); - subSocket.Connect(endpoint.Url); - subSocket.SubscribeAll(); - - if (subSocket.CurveServerKey != null) - logger.Info($"Monitoring Bt-Stream source {endpoint.Url} using Curve public-key {subSocket.CurveServerKey.ToHexString()}"); - else - logger.Info($"Monitoring Bt-Stream source {endpoint.Url}"); - - return subSocket; - }).ToArray(); + var sockets = relays.Select(SetupSubSocket).ToArray(); using (new CompositeDisposable(sockets)) { - var urls = endpoints.Select(x => x.Url).ToArray(); var pollItems = sockets.Select(_ => ZPollItem.CreateReceiver()).ToArray(); while (!cts.IsCancellationRequested) @@ -90,27 +80,30 @@ private void StartMessageReceiver(ZmqPubSubEndpointConfig[] endpoints) if (msg != null) { - lastMessageReceived = clock.Now; + lastMessageReceived[i] = clock.Now; using (msg) { ProcessMessage(msg); } } + + else if (clock.Now - lastMessageReceived[i] > reconnectTimeout) + { + // re-create socket + sockets[i].Dispose(); + sockets[i] = SetupSubSocket(relays[i]); + + // reset clock + lastMessageReceived[i] = clock.Now; + + logger.Info(() => $"Receive timeout of {reconnectTimeout.TotalSeconds} seconds exceeded. Re-connecting to {relays[i].Url} ..."); + } } if (error != null) logger.Error(() => $"{nameof(ShareReceiver)}: {error.Name} [{error.Name}] during receive"); } - - else - { - if (clock.Now - lastMessageReceived > reconnectTimeout) - { - logger.Info(() => $"Receive timeout of {reconnectTimeout.TotalSeconds} seconds exceeded. Re-connecting ..."); - break; - } - } } } } @@ -126,6 +119,21 @@ private void StartMessageReceiver(ZmqPubSubEndpointConfig[] endpoints) }, cts.Token); } + private static ZSocket SetupSubSocket(ZmqPubSubEndpointConfig relay) + { + var subSocket = new ZSocket(ZSocketType.SUB); + subSocket.SetupCurveTlsClient(relay.SharedEncryptionKey, logger); + subSocket.Connect(relay.Url); + subSocket.SubscribeAll(); + + if (subSocket.CurveServerKey != null) + logger.Info($"Monitoring Bt-Stream source {relay.Url} using Curve public-key {subSocket.CurveServerKey.ToHexString()}"); + else + logger.Info($"Monitoring Bt-Stream source {relay.Url}"); + + return subSocket; + } + private void ProcessMessage(ZMessage msg) { // extract frames From a64a8910c93469a3e9f9bf92321a8c26bd896c2e Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Thu, 8 Nov 2018 09:55:44 +0100 Subject: [PATCH 031/178] Disable hashrate modifier --- src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs index ce673c407..8721ee463 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs @@ -371,7 +371,7 @@ public override double HashrateFromShares(double shares, double interval) var multiplier = BitcoinConstants.Pow2x32; var result = shares * multiplier / interval; - result *= coin.HashrateMultiplier; + //result *= coin.HashrateMultiplier; return result; } From 366b930ff0161f32427cef2f8bc9e4f5d7ddf99d Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Thu, 8 Nov 2018 10:21:30 +0100 Subject: [PATCH 032/178] WIP --- src/Miningcore/Mining/StatsRecorder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Mining/StatsRecorder.cs b/src/Miningcore/Mining/StatsRecorder.cs index f9827e8de..91247b0ab 100644 --- a/src/Miningcore/Mining/StatsRecorder.cs +++ b/src/Miningcore/Mining/StatsRecorder.cs @@ -56,7 +56,7 @@ public StatsRecorder(IComponentContext ctx, private readonly ConcurrentDictionary pools = new ConcurrentDictionary(); private const int HashrateCalculationWindow = 1200; // seconds private const int MinHashrateCalculationWindow = 300; // seconds - private const double HashrateBoostFactor = 1.07d; + private const double HashrateBoostFactor = 1.1d; private ClusterConfig clusterConfig; private Thread thread1; private const int RetryCount = 4; From f9d9d9c9ce4350d2398d7175c017b122547e5cf1 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Thu, 8 Nov 2018 14:07:25 +0100 Subject: [PATCH 033/178] Use ValueTask in some hotspots that mostly complete synchronously --- .../Blockchain/Bitcoin/BitcoinJobManager.cs | 2 +- .../Bitcoin/BitcoinJobManagerBase.cs | 2 +- .../Cryptonote/CryptonoteJobManager.cs | 2 +- .../Blockchain/Equihash/EquihashJobManager.cs | 2 +- .../Blockchain/Ethereum/EthereumJob.cs | 6 ++- .../Blockchain/Ethereum/EthereumJobManager.cs | 7 ++- .../Blockchain/Ethereum/EthereumPool.cs | 3 +- src/Miningcore/Crypto/Hashing/Ethash/Dag.cs | 7 +-- .../Crypto/Hashing/Ethash/EthashFull.cs | 7 +-- src/Miningcore/Miningcore.csproj | 1 + src/Miningcore/Stratum/StratumClient.cs | 54 +++++++------------ 11 files changed, 39 insertions(+), 54 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index 44d52c1aa..f2b3944ca 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -206,7 +206,7 @@ public override object[] GetSubscriberData(StratumClient worker) return responseData; } - public override async Task SubmitShareAsync(StratumClient worker, object submission, + public override async ValueTask SubmitShareAsync(StratumClient worker, object submission, double stratumDifficultyBase, CancellationToken ct) { Contract.RequiresNonNull(worker, nameof(worker)); diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index 2b1b6b1a0..2b36d3a9f 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -632,7 +632,7 @@ public virtual async Task ValidateAddressAsync(string address, Cancellatio public abstract object[] GetSubscriberData(StratumClient worker); - public abstract Task SubmitShareAsync(StratumClient worker, object submission, + public abstract ValueTask SubmitShareAsync(StratumClient worker, object submission, double stratumDifficultyBase, CancellationToken ct); #endregion // API-Surface diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs index fbdc136e9..f7b588e54 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs @@ -307,7 +307,7 @@ public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out } } - public async Task SubmitShareAsync(StratumClient worker, + public async ValueTask SubmitShareAsync(StratumClient worker, CryptonoteSubmitShareRequest request, CryptonoteWorkerJob workerJob, double stratumDifficultyBase, CancellationToken ct) { Contract.RequiresNonNull(worker, nameof(worker)); diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index 274f3ba49..b12bc1e38 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -237,7 +237,7 @@ public override object[] GetSubscriberData(StratumClient worker) return responseData; } - public override async Task SubmitShareAsync(StratumClient worker, object submission, + public override async ValueTask SubmitShareAsync(StratumClient worker, object submission, double stratumDifficultyBase, CancellationToken ct) { Contract.RequiresNonNull(worker, nameof(worker)); diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs b/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs index 0df6a9043..dbf20a688 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Numerics; +using System.Threading; using System.Threading.Tasks; using Miningcore.Crypto.Hashing.Ethash; using Miningcore.Extensions; @@ -53,7 +54,8 @@ private void RegisterNonce(StratumClient worker, string nonce) } } - public async Task<(Share Share, string FullNonceHex, string HeaderHash, string MixHash)> ProcessShareAsync(StratumClient worker, string nonce, EthashFull ethash) + public async ValueTask<(Share Share, string FullNonceHex, string HeaderHash, string MixHash)> ProcessShareAsync( + StratumClient worker, string nonce, EthashFull ethash, CancellationToken ct) { // duplicate nonce? lock(workerNonces) @@ -69,7 +71,7 @@ private void RegisterNonce(StratumClient worker, string nonce) throw new StratumException(StratumError.MinusOne, "bad nonce " + fullNonceHex); // get dag for block - var dag = await ethash.GetDagAsync(BlockTemplate.Height, logger); + var dag = await ethash.GetDagAsync(BlockTemplate.Height, logger, ct); // compute if (!dag.Compute(logger, BlockTemplate.Header.HexToByteArray(), fullNonce, out var mixDigest, out var resultBytes)) diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs index 0b8c19383..43a1f9fb1 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs @@ -437,8 +437,7 @@ public void PrepareWorker(StratumClient client) context.ExtraNonce1 = extraNonceProvider.Next(); } - public async Task SubmitShareAsync(StratumClient worker, - string[] request, double stratumDifficulty, double stratumDifficultyBase, CancellationToken ct) + public async ValueTask SubmitShareAsync(StratumClient worker, string[] request, CancellationToken ct) { Contract.RequiresNonNull(worker, nameof(worker)); Contract.RequiresNonNull(request, nameof(request)); @@ -459,7 +458,7 @@ public async Task SubmitShareAsync(StratumClient worker, } // validate & process - var (share, fullNonceHex, headerHash, mixHash) = await job.ProcessShareAsync(worker, nonce, ethash); + var (share, fullNonceHex, headerHash, mixHash) = await job.ProcessShareAsync(worker, nonce, ethash, ct); // enrich share with common data share.PoolId = poolConfig.Id; @@ -621,7 +620,7 @@ protected override async Task PostStartInitAsync(CancellationToken ct) { logger.Info(() => $"Loading current DAG ..."); - await ethash.GetDagAsync(blockTemplate.Height, logger); + await ethash.GetDagAsync(blockTemplate.Height, logger, ct); logger.Info(() => $"Loaded current DAG"); break; diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs b/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs index 354e910cd..5ef684e1c 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs @@ -175,8 +175,7 @@ private async Task OnSubmitAsync(StratumClient client, Timestamped(!string.IsNullOrEmpty(dagDir), $"{nameof(dagDir)} must not be empty"); @@ -86,7 +86,8 @@ await Task.Run(() => handle = LibMultihash.ethash_full_new(dagDir, light, progress => { logger.Info(() => $"Generating DAG for epoch {Epoch}: {progress}%"); - return 0; + + return !ct.IsCancellationRequested ? 0 : 1; }); if (handle == IntPtr.Zero) @@ -106,7 +107,7 @@ await Task.Run(() => { sem.Release(); } - }); + }, ct); } } diff --git a/src/Miningcore/Crypto/Hashing/Ethash/EthashFull.cs b/src/Miningcore/Crypto/Hashing/Ethash/EthashFull.cs index aa6102781..ee6b6f6c5 100644 --- a/src/Miningcore/Crypto/Hashing/Ethash/EthashFull.cs +++ b/src/Miningcore/Crypto/Hashing/Ethash/EthashFull.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Miningcore.Blockchain.Ethereum; using Miningcore.Contracts; @@ -30,7 +31,7 @@ public void Dispose() value.Dispose(); } - public async Task GetDagAsync(ulong block, ILogger logger) + public async Task GetDagAsync(ulong block, ILogger logger, CancellationToken ct) { var epoch = block / EthereumConstants.EpochLength; Dag result; @@ -79,14 +80,14 @@ public async Task GetDagAsync(ulong block, ILogger logger) future = new Dag(epoch + 1); #pragma warning disable 4014 - future.GenerateAsync(dagDir, logger); + future.GenerateAsync(dagDir, logger, ct); #pragma warning restore 4014 } result.LastUsed = DateTime.Now; } - await result.GenerateAsync(dagDir, logger); + await result.GenerateAsync(dagDir, logger, ct); return result; } } diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index a1d812fcc..fbda6b456 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -45,6 +45,7 @@ + diff --git a/src/Miningcore/Stratum/StratumClient.cs b/src/Miningcore/Stratum/StratumClient.cs index 559329f96..fd6c40b23 100644 --- a/src/Miningcore/Stratum/StratumClient.cs +++ b/src/Miningcore/Stratum/StratumClient.cs @@ -198,39 +198,28 @@ public T ContextAs() where T : WorkerContextBase return (T)context; } - public Task RespondAsync(T payload, object id) + public ValueTask RespondAsync(T payload, object id) { - Contract.RequiresNonNull(payload, nameof(payload)); - Contract.RequiresNonNull(id, nameof(id)); - return RespondAsync(new JsonRpcResponse(payload, id)); } - public Task RespondErrorAsync(StratumError code, string message, object id, object result = null, object data = null) + public ValueTask RespondErrorAsync(StratumError code, string message, object id, object result = null, object data = null) { - Contract.RequiresNonNull(message, nameof(message)); - return RespondAsync(new JsonRpcResponse(new JsonRpcException((int)code, message, null), id, result)); } - public Task RespondAsync(JsonRpcResponse response) + public ValueTask RespondAsync(JsonRpcResponse response) { - Contract.RequiresNonNull(response, nameof(response)); - return SendAsync(response); } - public Task NotifyAsync(string method, T payload) + public ValueTask NotifyAsync(string method, T payload) { - Contract.Requires(!string.IsNullOrEmpty(method), $"{nameof(method)} must not be empty"); - return NotifyAsync(new JsonRpcRequest(method, payload, null)); } - public Task NotifyAsync(JsonRpcRequest request) + public ValueTask NotifyAsync(JsonRpcRequest request) { - Contract.RequiresNonNull(request, nameof(request)); - return SendAsync(request); } @@ -238,23 +227,13 @@ public void Disconnect() { networkStream.Close(); } - - private static JsonRpcRequest DeserializeRequest(ReadOnlySequence lineBuffer) - { - JsonRpcRequest request; - - using (var jr = new JsonTextReader(new StreamReader(new MemoryStream(lineBuffer.ToArray()), StratumConstants.Encoding))) - { - request = serializer.Deserialize(jr); - } - - return request; - } #endregion // API-Surface - private async Task SendAsync(T payload) + private async ValueTask SendAsync(T payload) { + Contract.RequiresNonNull(payload, nameof(payload)); + using (var ctsTimeout = new CancellationTokenSource()) { using (var ctsComposite = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, ctsTimeout.Token)) @@ -389,13 +368,16 @@ private async Task ProcessRequestAsync( Func onRequestAsync, ReadOnlySequence lineBuffer) { - var request = DeserializeRequest(lineBuffer); - - if (request == null) - throw new JsonException("Unable to deserialize request"); - - // Dispatch - await onRequestAsync(this, request, cts.Token); + using (var reader = new JsonTextReader(new StreamReader(new MemoryStream(lineBuffer.ToArray()), StratumConstants.Encoding))) + { + var request = serializer.Deserialize(reader); + + if (request == null) + throw new JsonException("Unable to deserialize request"); + + // Dispatch + await onRequestAsync(this, request, cts.Token); + } } /// From c688f42f8b016e3746ce28694c1102d2ff001ef9 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Thu, 8 Nov 2018 20:33:11 +0100 Subject: [PATCH 034/178] PAC --- src/Miningcore/coins.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index d8925a8f4..554ce82a3 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -195,6 +195,25 @@ "explorerTxLink": "https://chainz.cryptoid.info/dash/tx.dws?{0}.htm", "explorerAccountLink": "https://chainz.cryptoid.info/dash/address.dws?{0}.htm" }, + "paccoin": { + "name": "Paccoin", + "symbol": "PAC", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "x11" + }, + "blockHasher": { + "hash": "reverse", + "args": [{ "hash": "x11" }] + }, + "hasMasterNodes": true, + "explorerBlockLink": "http://explorer.paccoin.net/block/$hash$", + "explorerTxLink": "http://explorer.paccoin.net/tx/{0}", + "explorerAccountLink": "http://explorer.paccoin.net/address/{0}" + }, "groestlcoin": { "name": "GroestlCoin", "symbol": "GRS", From c9f9b7ef0950566649e402583daf5c174fbe3ffd Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 9 Nov 2018 07:51:26 +0100 Subject: [PATCH 035/178] Scrap HashrateMultiplier --- src/Miningcore/Configuration/ClusterConfig.cs | 4 ---- src/Miningcore/coins.json | 14 +------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index e74f893a7..aeecfc8f1 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -140,10 +140,6 @@ public partial class BitcoinTemplate : CoinTemplate [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] [DefaultValue(1.0d)] public double ShareMultiplier { get; set; } = 1.0d; - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - [DefaultValue(1.0d)] - public double HashrateMultiplier { get; set; } = 1.0d; } public enum EquihashSubfamily diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index 554ce82a3..d4bd06980 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -96,7 +96,6 @@ ] }, "shareMultiplier": 65536, - "hashrateMultiplier": 1.5, "explorerBlockLink": "https://chainz.cryptoid.info/ltc/block.dws?$height$.htm", "explorerTxLink": "https://chainz.cryptoid.info/ltc/tx.dws?{0}.htm", "explorerAccountLink": "https://chainz.cryptoid.info/ltc/address.dws?{0}.htm" @@ -144,7 +143,6 @@ ] }, "shareMultiplier": 65536, - "hashrateMultiplier": 1.5, "explorerBlockLink": "https://dogechain.info/block/$height$", "explorerTxLink": "https://dogechain.info/tx/{0}", "explorerAccountLink": "https://dogechain.info/address/{0}" @@ -173,8 +171,7 @@ } ] }, - "shareMultiplier": 65536, - "hashrateMultiplier": 1.5 + "shareMultiplier": 65536 }, "dash": { "name": "Dash", @@ -248,7 +245,6 @@ "args": [{ "hash": "sha256d" }] }, "shareMultiplier": 256, - "hashrateMultiplier": 4, "explorerBlockLink": "https://bchain.info/MONA/block/$height$", "explorerTxLink": "https://bchain.info/MONA/tx/{0}", "explorerAccountLink": "https://bchain.info/MONA/addr/{0}" @@ -268,7 +264,6 @@ "args": [{ "hash": "sha256d" }] }, "shareMultiplier": 256, - "hashrateMultiplier": 4, "explorerBlockLink": "https://chainz.cryptoid.info/vtc/block.dws?$height$.htm", "explorerTxLink": "https://chainz.cryptoid.info/vtc/tx.dws?{0}.htm", "explorerAccountLink": "https://chainz.cryptoid.info/vtc/address.dws?{0}.htm" @@ -316,7 +311,6 @@ ] }, "shareMultiplier": 65536, - "hashrateMultiplier": 1.5, "explorerBlockLink": "https://chainz.cryptoid.info/moon/block.dws?$height$.htm", "explorerTxLink": "https://chainz.cryptoid.info/moon/tx.dws?{0}.htm", "explorerAccountLink": "https://chainz.cryptoid.info/moon/address.dws?{0}.htm" @@ -346,7 +340,6 @@ ] }, "shareMultiplier": 65536, - "hashrateMultiplier": 1.5, "explorerBlockLink": "https://chainz.cryptoid.info/pak/block.dws?$height$.htm", "explorerTxLink": "https://chainz.cryptoid.info/pak/tx.dws?{0}.htm", "explorerAccountLink": "https://chainz.cryptoid.info/pak/address.dws?{0}.htm" @@ -452,7 +445,6 @@ "coinbaseTxVersion": 2, "coinbaseTxAppendData": "Flo Miningcore", "shareMultiplier": 65536, - "hashrateMultiplier": 1.5, "explorerBlockLink": "https://florincoin.info/block/0", "explorerTxLink": "https://florincoin.info/tx/{0}", "explorerAccountLink": "https://florincoin.info/address/{0}" @@ -491,7 +483,6 @@ "args": [{ "hash": "sha256d" }] }, "shareMultiplier": 65536, - "hashrateMultiplier": 1.5, "explorerBlockLink": "https://digiexplorer.info/block/$height$", "explorerTxLink": "https://digiexplorer.info/tx/{0}", "explorerAccountLink": "https://digiexplorer.info/address/{0}" @@ -571,7 +562,6 @@ ] }, "shareMultiplier": 256, - "hashrateMultiplier": 4, "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", "explorerTxLink": "https://verge-blockchain.info/tx/{0}", "explorerAccountLink": "https://verge-blockchain.info/address/{0}" @@ -597,7 +587,6 @@ ] }, "shareMultiplier": 65536, - "hashrateMultiplier": 1.5, "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", "explorerTxLink": "https://verge-blockchain.info/tx/{0}", "explorerAccountLink": "https://verge-blockchain.info/address/{0}" @@ -621,7 +610,6 @@ } ] }, - "hashrateMultiplier": 2.55, "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", "explorerTxLink": "https://verge-blockchain.info/tx/{0}", "explorerAccountLink": "https://verge-blockchain.info/address/{0}" From dde77d7d070fc1c2942965a21cb8a1424208fe9c Mon Sep 17 00:00:00 2001 From: bitspill Date: Fri, 9 Nov 2018 11:46:42 -0800 Subject: [PATCH 036/178] Florincoin -> Flo (#465) --- examples/flo_pool.json | 3 +-- src/Miningcore/coins.json | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/examples/flo_pool.json b/examples/flo_pool.json index d2c566f61..600c6dd7c 100644 --- a/examples/flo_pool.json +++ b/examples/flo_pool.json @@ -46,7 +46,7 @@ { "id": "flo1", "enabled": true, - "coin": "florincoin", + "coin": "flo", "address": "FC3d6JT1Z3uZvKVNWjKt3qN8PX8knhAU7d", "rewardRecipients": [ { @@ -54,7 +54,6 @@ "percentage": 1.0 } ], - "floData": "Flo MiningCore", "maxActiveJobs": 10, "blockRefreshInterval": 500, "jobRebroadcastTimeout": 10, diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index d4bd06980..bb740c5e8 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -418,8 +418,8 @@ "explorerTxLink": "http://explorer.btcd.io/#/TX?TX={0}", "explorerAccountLink": "http://explorer.btcd.io/#/address?address={0}" }, - "florincoin": { - "name": "Florincoin", + "flo": { + "name": "Flo", "symbol": "FLO", "family": "bitcoin", "coinbaseHasher": { @@ -445,9 +445,9 @@ "coinbaseTxVersion": 2, "coinbaseTxAppendData": "Flo Miningcore", "shareMultiplier": 65536, - "explorerBlockLink": "https://florincoin.info/block/0", - "explorerTxLink": "https://florincoin.info/tx/{0}", - "explorerAccountLink": "https://florincoin.info/address/{0}" + "explorerBlockLink": "https://network.flo.cash/block/0", + "explorerTxLink": "https://network.flo.cash/tx/{0}", + "explorerAccountLink": "https://network.flo.cash/address/{0}" }, "digibyte-sha256": { "name": "Digibyte-Sha256", From 9b8a3cfd2bef9e9ce043cb15bfa4ee2dc0be4822 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 9 Nov 2018 21:10:13 +0100 Subject: [PATCH 037/178] Revert FLO explorer links (for now) --- src/Miningcore/coins.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index bb740c5e8..bed7d4c45 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -445,9 +445,9 @@ "coinbaseTxVersion": 2, "coinbaseTxAppendData": "Flo Miningcore", "shareMultiplier": 65536, - "explorerBlockLink": "https://network.flo.cash/block/0", - "explorerTxLink": "https://network.flo.cash/tx/{0}", - "explorerAccountLink": "https://network.flo.cash/address/{0}" + "explorerBlockLink": "https://florincoin.info/block/$hash$", + "explorerTxLink": "https://florincoin.info/tx/{0}", + "explorerAccountLink": "https://florincoin.info/address/{0}" }, "digibyte-sha256": { "name": "Digibyte-Sha256", From fc3a9d2cfc5bee9ff3ac747fb423cfa854e59028 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 9 Nov 2018 21:42:33 +0100 Subject: [PATCH 038/178] Capitalize FLO --- src/Miningcore/coins.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index bed7d4c45..8a9caecd1 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -419,7 +419,7 @@ "explorerAccountLink": "http://explorer.btcd.io/#/address?address={0}" }, "flo": { - "name": "Flo", + "name": "FLO", "symbol": "FLO", "family": "bitcoin", "coinbaseHasher": { From 5fd8d4c23af3c7064883ec54b0165ffdf3174112 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 9 Nov 2018 21:43:31 +0100 Subject: [PATCH 039/178] WIP --- src/Miningcore/coins.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index 8a9caecd1..62571615b 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -443,7 +443,7 @@ ] }, "coinbaseTxVersion": 2, - "coinbaseTxAppendData": "Flo Miningcore", + "coinbaseTxAppendData": "FLO Miningcore", "shareMultiplier": 65536, "explorerBlockLink": "https://florincoin.info/block/$hash$", "explorerTxLink": "https://florincoin.info/tx/{0}", From 144d3fd97586225574f94cbb5b72cced72f42472 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 9 Nov 2018 22:18:08 +0100 Subject: [PATCH 040/178] Config overridable coinbase tx comments --- .../Blockchain/Bitcoin/BitcoinJobTests.cs | 4 ++-- src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs | 12 +++++++++--- .../Blockchain/Bitcoin/BitcoinJobManager.cs | 2 +- .../Bitcoin/Configuration/BitcoinPoolConfigExtra.cs | 6 ++++++ src/Miningcore/Configuration/ClusterConfig.cs | 5 ++++- src/Miningcore/coins.json | 2 +- 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs b/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs index aa882e358..1e378da14 100644 --- a/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs +++ b/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs @@ -50,7 +50,7 @@ public void BitcoinJob_Should_Accept_Valid_Share() // set clock to job creation time var clock = new MockMasterClock { CurrentTime = DateTimeOffset.FromUnixTimeSeconds(1508869874).UtcDateTime }; - job.Init(bt, "1", poolConfig, clusterConfig, clock, poolAddressDestination, Network.RegTest, + job.Init(bt, "1", poolConfig, null, clusterConfig, clock, poolAddressDestination, Network.RegTest, false, 1, sha256d, sha256d, sha256dReverse); // set clock to submission time @@ -85,7 +85,7 @@ public void BitcoinJob_Should_Not_Accept_Invalid_Share() // set clock to job creation time var clock = new MockMasterClock { CurrentTime = DateTimeOffset.FromUnixTimeSeconds(1508869874).UtcDateTime }; - job.Init(bt, "1", poolConfig, clusterConfig, clock, poolAddressDestination, Network.RegTest, + job.Init(bt, "1", poolConfig, null, clusterConfig, clock, poolAddressDestination, Network.RegTest, false, 1, sha256d, sha256d, sha256dReverse); // set clock to submission time diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs index 07a8ed16d..6faca522a 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs @@ -24,6 +24,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using System.IO; using System.Linq; using System.Text; +using Miningcore.Blockchain.Bitcoin.Configuration; using Miningcore.Blockchain.Bitcoin.DaemonResponses; using Miningcore.Configuration; using Miningcore.Crypto; @@ -47,6 +48,7 @@ public class BitcoinJob protected int extraNoncePlaceHolderLength; protected IHashAlgorithm headerHasher; protected bool isPoS; + protected string txComment; protected Network network; protected IDestination poolAddressDestination; @@ -169,9 +171,9 @@ protected virtual void BuildCoinbase() protected virtual void AppendCoinbaseFinal(BitcoinStream bs) { - if (!string.IsNullOrEmpty(coin.CoinbaseTxAppendData)) + if (!string.IsNullOrEmpty(txComment)) { - var data = Encoding.ASCII.GetBytes(coin.CoinbaseTxAppendData); + var data = Encoding.ASCII.GetBytes(txComment); bs.ReadWriteAsVarString(ref data); } } @@ -504,7 +506,8 @@ protected virtual Money CreateMasternodeOutputs(Transaction tx, Money reward) public string JobId { get; protected set; } public void Init(BlockTemplate blockTemplate, string jobId, - PoolConfig poolConfig, ClusterConfig clusterConfig, IMasterClock clock, + PoolConfig poolConfig, BitcoinPoolConfigExtra extraPoolConfig, + ClusterConfig clusterConfig, IMasterClock clock, IDestination poolAddressDestination, Network network, bool isPoS, double shareMultiplier, IHashAlgorithm coinbaseHasher, IHashAlgorithm headerHasher, IHashAlgorithm blockHasher) @@ -532,6 +535,9 @@ public void Init(BlockTemplate blockTemplate, string jobId, this.isPoS = isPoS; this.shareMultiplier = shareMultiplier; + txComment = !string.IsNullOrEmpty(extraPoolConfig?.CoinbaseTxComment) ? + extraPoolConfig.CoinbaseTxComment : coin.CoinbaseTxComment; + if (coin.HasMasterNodes) masterNodeParameters = BlockTemplate.Extra.SafeExtensionDataAs(); diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index f2b3944ca..046ccd851 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -118,7 +118,7 @@ private BitcoinJob CreateJob() job = CreateJob(); job.Init(blockTemplate, NextJobId(), - poolConfig, clusterConfig, clock, poolAddressDestination, network, isPoS, + poolConfig, extraPoolConfig, clusterConfig, clock, poolAddressDestination, network, isPoS, ShareMultiplier, coin.CoinbaseHasherValue, coin.HeaderHasherValue, !isPoS ? coin.BlockHasherValue : coin.PoSBlockHasherValue ?? coin.BlockHasherValue); diff --git a/src/Miningcore/Blockchain/Bitcoin/Configuration/BitcoinPoolConfigExtra.cs b/src/Miningcore/Blockchain/Bitcoin/Configuration/BitcoinPoolConfigExtra.cs index 443455285..05a22da4f 100644 --- a/src/Miningcore/Blockchain/Bitcoin/Configuration/BitcoinPoolConfigExtra.cs +++ b/src/Miningcore/Blockchain/Bitcoin/Configuration/BitcoinPoolConfigExtra.cs @@ -37,6 +37,12 @@ public class BitcoinPoolConfigExtra /// public bool? HasLegacyDaemon { get; set; } + /// + /// Arbitrary string appended at end of coinbase tx + /// Overrides property of same name from BitcoinTemplate + /// + public string CoinbaseTxComment { get; set; } + /// /// Blocktemplate stream published via ZMQ /// diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index aeecfc8f1..f76b28642 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -132,7 +132,10 @@ public partial class BitcoinTemplate : CoinTemplate [DefaultValue(1u)] public uint CoinbaseTxVersion { get; set; } - public string CoinbaseTxAppendData { get; set; } + /// + /// Default transaction comment for coins that REQUIRE tx comments + /// + public string CoinbaseTxComment { get; set; } [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool HasMasterNodes { get; set; } diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index 62571615b..bd17ef8b4 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -443,7 +443,7 @@ ] }, "coinbaseTxVersion": 2, - "coinbaseTxAppendData": "FLO Miningcore", + "coinbaseTxComment": "FLO Miningcore", "shareMultiplier": 65536, "explorerBlockLink": "https://florincoin.info/block/$hash$", "explorerTxLink": "https://florincoin.info/tx/{0}", From ea567813c217e0df8748a0e498251eec054a31e8 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sat, 10 Nov 2018 12:51:29 +0100 Subject: [PATCH 041/178] Update flo explorer links to new domain but leave as http --- src/Miningcore/coins.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index bd17ef8b4..187b4b3fe 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -445,9 +445,9 @@ "coinbaseTxVersion": 2, "coinbaseTxComment": "FLO Miningcore", "shareMultiplier": 65536, - "explorerBlockLink": "https://florincoin.info/block/$hash$", - "explorerTxLink": "https://florincoin.info/tx/{0}", - "explorerAccountLink": "https://florincoin.info/address/{0}" + "explorerBlockLink": "http://network.flo.cash/block/$hash$", + "explorerTxLink": "http://network.flo.cash/tx/{0}", + "explorerAccountLink": "http://network.flo.cash/address/{0}" }, "digibyte-sha256": { "name": "Digibyte-Sha256", From 2beeb2a17323b1757dada7914133018fe5edcbb0 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sat, 10 Nov 2018 14:40:52 +0100 Subject: [PATCH 042/178] Improved http connection pooling --- src/Miningcore/Configuration/ClusterConfig.cs | 5 --- .../DaemonInterface/DaemonClient.cs | 32 +++++-------------- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index f76b28642..9907328b1 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -356,11 +356,6 @@ public class DaemonEndpointConfig : AuthenticatedNetworkEndpointConfig /// public bool Http2 { get; set; } - /// - /// Validate SSL certificate (if SSL option is set to true) - default is false - /// - public bool ValidateCert { get; set; } - /// /// Optional endpoint category /// diff --git a/src/Miningcore/DaemonInterface/DaemonClient.cs b/src/Miningcore/DaemonInterface/DaemonClient.cs index 39e56e846..ec5d715b7 100644 --- a/src/Miningcore/DaemonInterface/DaemonClient.cs +++ b/src/Miningcore/DaemonInterface/DaemonClient.cs @@ -73,7 +73,7 @@ public DaemonClient(JsonSerializerSettings serializerSettings, IMessageBus messa private readonly JsonSerializerSettings serializerSettings; protected DaemonEndpointConfig[] endPoints; - private Dictionary httpClients; + private HttpClient httpClient; private readonly JsonSerializer serializer; // Telemetry @@ -96,29 +96,14 @@ public void Configure(DaemonEndpointConfig[] endPoints, string digestAuthRealm = this.endPoints = endPoints; - // create one HttpClient instance per endpoint that carries the associated credentials - httpClients = endPoints.ToDictionary(endpoint => endpoint, endpoint => + httpClient = new HttpClient(new SocketsHttpHandler { - var handler = new SocketsHttpHandler - { - AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, - }; - - if(!string.IsNullOrEmpty(endpoint.User)) - { - handler.Credentials = new NetworkCredential(endpoint.User, endpoint.Password); - handler.PreAuthenticate = true; - } + AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, - if ((endpoint.Ssl || endpoint.Http2) && !endpoint.ValidateCert) + SslOptions = new SslClientAuthenticationOptions { - handler.SslOptions = new SslClientAuthenticationOptions - { - RemoteCertificateValidationCallback = ((sender, certificate, chain, errors) => true), - }; + RemoteCertificateValidationCallback = ((sender, certificate, chain, errors) => true), } - - return new HttpClient(handler); }); } @@ -352,7 +337,7 @@ private async Task BuildRequestTask(ILogger logger, DaemonEndpo logger.Trace(() => $"Sending RPC request to {requestUrl}: {json}"); // send request - using (var response = await httpClients[endPoint].SendAsync(request, ct)) + using (var response = await httpClient.SendAsync(request, ct)) { // read response var responseContent = await response.Content.ReadAsStringAsync(); @@ -410,7 +395,7 @@ private async Task[]> BuildBatchRequestTask(ILogger logg logger.Trace(() => $"Sending RPC request to {requestUrl}: {json}"); // send request - using(var response = await httpClients[endPoint].SendAsync(request)) + using(var response = await httpClient.SendAsync(request)) { // deserialize response var jsonResponse = await response.Content.ReadAsStringAsync(); @@ -521,8 +506,7 @@ private IObservable WebsocketSubscribeEndpoint(ILogger logger, DaemonEnd var protocol = conf.Ssl ? "wss" : "ws"; var uri = new Uri($"{protocol}://{endPoint.Host}:{conf.Port}{conf.HttpPath}"); - if(!endPoint.ValidateCert) - client.Options.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; + client.Options.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; logger.Debug(() => $"Establishing WebSocket connection to {uri}"); await client.ConnectAsync(uri, cts.Token); From 81d5650161000f25841bec351291428f331bdbb7 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sat, 10 Nov 2018 15:41:40 +0100 Subject: [PATCH 043/178] MessageBusExtensions --- .../Bitcoin/BitcoinPayoutHandler.cs | 18 ++----- .../Cryptonote/CryptonotePayoutHandler.cs | 19 ++------ .../Ethereum/EthereumPayoutHandler.cs | 31 ++---------- .../Extensions/MessageBusExtensions.cs | 48 +++++++++++++++++++ src/Miningcore/Mining/ShareRecorder.cs | 2 +- .../Messages/BlockNotification.cs | 4 +- 6 files changed, 62 insertions(+), 60 deletions(-) create mode 100644 src/Miningcore/Extensions/MessageBusExtensions.cs diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs index 88cc335c5..1258e5d14 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs @@ -166,7 +166,7 @@ public virtual async Task ClassifyBlocksAsync(Block[] blocks) block.Reward = transactionInfo.Amount; // update actual block-reward from coinbase-tx result.Add(block); - messageBus.SendMessage(new BlockConfirmationProgressNotification(block.ConfirmationProgress, poolConfig.Id, block.BlockHeight, coin.Symbol)); + messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); break; case "generate": @@ -178,18 +178,7 @@ public virtual async Task ClassifyBlocksAsync(Block[] blocks) logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); - // build explorer link - string explorerLink = null; - if (coin.ExplorerBlockLinks.TryGetValue(!string.IsNullOrEmpty(block.Type) ? block.Type : "block", out var blockInfobaseUrl)) - { - if (blockInfobaseUrl.Contains(CoinMetaData.BlockHeightPH)) - explorerLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHeightPH, block.BlockHeight.ToString(CultureInfo.InvariantCulture)); - else if (blockInfobaseUrl.Contains(CoinMetaData.BlockHashPH) && !string.IsNullOrEmpty(block.Hash)) - explorerLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHashPH, block.Hash); - } - - messageBus.SendMessage(new BlockUnlockedNotification(block.Status, poolConfig.Id, - block.BlockHeight, block.Hash, block.Miner, coin.Symbol, explorerLink)); + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); break; default: @@ -199,8 +188,7 @@ public virtual async Task ClassifyBlocksAsync(Block[] blocks) block.Reward = 0; result.Add(block); - messageBus.SendMessage(new BlockUnlockedNotification(block.Status, poolConfig.Id, - block.BlockHeight, block.Hash, block.Miner, coin.Symbol, null)); + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); break; } } diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs index 603d57370..e13039d31 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs @@ -392,7 +392,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) block.ConfirmationProgress = Math.Min(1.0d, (double) blockHeader.Depth / CryptonoteConstants.PayoutMinBlockConfirmations); result.Add(block); - messageBus.SendMessage(new BlockConfirmationProgressNotification(block.ConfirmationProgress, poolConfig.Id, block.BlockHeight, coin.Symbol)); + messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); // orphaned? if (blockHeader.IsOrphaned || blockHeader.Hash != block.TransactionConfirmationData) @@ -400,9 +400,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) block.Status = BlockStatus.Orphaned; block.Reward = 0; - messageBus.SendMessage(new BlockUnlockedNotification(block.Status, poolConfig.Id, - block.BlockHeight, block.Hash, block.Miner, coin.Symbol, null)); - + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); continue; } @@ -415,18 +413,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); - // build explorer link - string explorerLink = null; - if (coin.ExplorerBlockLinks.TryGetValue(!string.IsNullOrEmpty(block.Type) ? block.Type : "block", out var blockInfobaseUrl)) - { - if (blockInfobaseUrl.Contains(CoinMetaData.BlockHeightPH)) - explorerLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHeightPH, block.BlockHeight.ToString(CultureInfo.InvariantCulture)); - else if (blockInfobaseUrl.Contains(CoinMetaData.BlockHashPH) && !string.IsNullOrEmpty(block.Hash)) - explorerLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHashPH, block.Hash); - } - - messageBus.SendMessage(new BlockUnlockedNotification(block.Status, poolConfig.Id, - block.BlockHeight, block.Hash, block.Miner, coin.Symbol, explorerLink)); + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); } } } diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs index 030c03cd1..7d3da1246 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs @@ -146,7 +146,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) block.ConfirmationProgress = Math.Min(1.0d, (double) (latestBlockHeight - block.BlockHeight) / EthereumConstants.MinConfimations); result.Add(block); - messageBus.SendMessage(new BlockConfirmationProgressNotification(block.ConfirmationProgress, poolConfig.Id, block.BlockHeight, coin.Symbol)); + messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); // is it block mined by us? if (blockInfo.Miner == poolConfig.Address) @@ -176,18 +176,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); - // build explorer link - string explorerLink = null; - if (coin.ExplorerBlockLinks.TryGetValue(!string.IsNullOrEmpty(block.Type) ? block.Type : "block", out var blockInfobaseUrl)) - { - if (blockInfobaseUrl.Contains(CoinMetaData.BlockHeightPH)) - explorerLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHeightPH, block.BlockHeight.ToString(CultureInfo.InvariantCulture)); - else if (blockInfobaseUrl.Contains(CoinMetaData.BlockHashPH) && !string.IsNullOrEmpty(block.Hash)) - explorerLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHashPH, block.Hash); - } - - messageBus.SendMessage(new BlockUnlockedNotification(block.Status, poolConfig.Id, - block.BlockHeight, block.Hash, block.Miner, coin.Symbol, explorerLink, block.Type)); + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); } continue; @@ -237,18 +226,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) logger.Info(() => $"[{LogCategory}] Unlocked uncle for block {blockInfo2.Height.Value} at height {uncle.Height.Value} worth {FormatAmount(block.Reward)}"); - // build explorer link - string explorerLink = null; - if (coin.ExplorerBlockLinks.TryGetValue(!string.IsNullOrEmpty(block.Type) ? block.Type : "block", out var blockInfobaseUrl)) - { - if (blockInfobaseUrl.Contains(CoinMetaData.BlockHeightPH)) - explorerLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHeightPH, block.BlockHeight.ToString(CultureInfo.InvariantCulture)); - else if (blockInfobaseUrl.Contains(CoinMetaData.BlockHashPH) && !string.IsNullOrEmpty(block.Hash)) - explorerLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHashPH, block.Hash); - } - - messageBus.SendMessage(new BlockUnlockedNotification(block.Status, poolConfig.Id, - block.BlockHeight, block.Hash, block.Miner, coin.Symbol, explorerLink, block.Type)); + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); } else @@ -265,8 +243,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) block.Status = BlockStatus.Orphaned; block.Reward = 0; - messageBus.SendMessage(new BlockUnlockedNotification(block.Status, poolConfig.Id, - block.BlockHeight, block.Hash, block.Miner, coin.Symbol, null)); + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); } } } diff --git a/src/Miningcore/Extensions/MessageBusExtensions.cs b/src/Miningcore/Extensions/MessageBusExtensions.cs new file mode 100644 index 000000000..0eae4a389 --- /dev/null +++ b/src/Miningcore/Extensions/MessageBusExtensions.cs @@ -0,0 +1,48 @@ +using Miningcore.Blockchain; +using Miningcore.Messaging; +using Miningcore.Persistence.Model; +using System.Globalization; +using Miningcore.Notifications.Messages; +using Miningcore.Configuration; + +namespace Miningcore.Extensions +{ + public static class MessageBusExtensions + { + public static void NotifyBlockFound(this IMessageBus messageBus, string poolId, ulong blockHeight, string symbol) + { + messageBus.SendMessage(new BlockFoundNotification(poolId, blockHeight, symbol)); + } + + public static void NotifyBlockConfirmationProgress(this IMessageBus messageBus, string poolId, Block block, CoinTemplate coin) + { + messageBus.SendMessage(new BlockConfirmationProgressNotification(block.ConfirmationProgress, poolId, block.BlockHeight, coin.Symbol)); + } + + public static void NotifyBlockUnlocked(this IMessageBus messageBus, string poolId, Block block, CoinTemplate coin) + { + // build explorer link + string blockExplorerLink = null; + string minerExplorerLink = null; + + if (block.Status != BlockStatus.Orphaned) + { + // block explorer link + if (coin.ExplorerBlockLinks.TryGetValue(!string.IsNullOrEmpty(block.Type) ? block.Type : "block", out var blockInfobaseUrl)) + { + if (blockInfobaseUrl.Contains(CoinMetaData.BlockHeightPH)) + blockExplorerLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHeightPH, block.BlockHeight.ToString(CultureInfo.InvariantCulture)); + else if (blockInfobaseUrl.Contains(CoinMetaData.BlockHashPH) && !string.IsNullOrEmpty(block.Hash)) + blockExplorerLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHashPH, block.Hash); + } + + // miner account explorer link + if (!string.IsNullOrEmpty(coin.ExplorerAccountLink)) + minerExplorerLink = string.Format(coin.ExplorerAccountLink, block.Miner); + } + + messageBus.SendMessage(new BlockUnlockedNotification(block.Status, poolId, + block.BlockHeight, block.Hash, block.Miner, minerExplorerLink, coin.Symbol, blockExplorerLink, block.Type)); + } + } +} diff --git a/src/Miningcore/Mining/ShareRecorder.cs b/src/Miningcore/Mining/ShareRecorder.cs index c3ed9634d..e848f9243 100644 --- a/src/Miningcore/Mining/ShareRecorder.cs +++ b/src/Miningcore/Mining/ShareRecorder.cs @@ -122,7 +122,7 @@ await cf.RunTx(async (con, tx) => blockEntity.Status = BlockStatus.Pending; await blockRepo.InsertAsync(con, tx, blockEntity); - messageBus.SendMessage(new BlockFoundNotification(share.PoolId, (ulong) share.BlockHeight, pools[share.PoolId].Template.Symbol)); + messageBus.NotifyBlockFound(share.PoolId, (ulong) share.BlockHeight, pools[share.PoolId].Template.Symbol); } }); } diff --git a/src/Miningcore/Notifications/Messages/BlockNotification.cs b/src/Miningcore/Notifications/Messages/BlockNotification.cs index 8be4d5fd6..d4fe7442b 100644 --- a/src/Miningcore/Notifications/Messages/BlockNotification.cs +++ b/src/Miningcore/Notifications/Messages/BlockNotification.cs @@ -58,7 +58,8 @@ public BlockConfirmationProgressNotification() public class BlockUnlockedNotification : BlockNotification { - public BlockUnlockedNotification(BlockStatus status, string poolId, ulong blockHeight, string blockHash, string miner, string symbol, string explorerLink, string blockType = "block") : + public BlockUnlockedNotification(BlockStatus status, string poolId, ulong blockHeight, string blockHash, + string miner, string minerExplorerLink, string symbol, string explorerLink, string blockType = "block") : base(poolId, blockHeight, symbol) { Status = status; @@ -77,5 +78,6 @@ public BlockUnlockedNotification() public string BlockHash { get; set; } public string Miner { get; set; } public string ExplorerLink { get; set; } + public string MinerExplorerLink { get; set; } } } From f973c12d10c65aeb89a9740b66a5b96f7691385a Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sat, 10 Nov 2018 15:47:17 +0100 Subject: [PATCH 044/178] .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 51e1b2227..5306a0881 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.user *.sln.docstates .vs/ +.vscode/ [Dd]ebug/ [Rr]elease/ From e617ab0619338bb13b7ef7aeba4074380d215543 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sun, 11 Nov 2018 09:42:57 +0100 Subject: [PATCH 045/178] Revert "Improved http connection pooling" and improved implementation This reverts commit 2beeb2a17323b1757dada7914133018fe5edcbb0. --- .../Cryptonote/CryptonoteJobManager.cs | 3 ++ src/Miningcore/Configuration/ClusterConfig.cs | 5 +++ .../DaemonInterface/DaemonClient.cs | 41 ++++++++++++++----- src/Miningcore/Payments/PayoutManager.cs | 17 +++++++- 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs index f7b588e54..b2fb8816e 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs @@ -252,6 +252,9 @@ public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfi if (string.IsNullOrEmpty(x.HttpPath)) x.HttpPath = CryptonoteConstants.DaemonRpcLocation; + // cryptonote daemons only support digest auth + x.DigestAuth = true; + return x; }) .ToArray(); diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index 9907328b1..9ceb01fb2 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -356,6 +356,11 @@ public class DaemonEndpointConfig : AuthenticatedNetworkEndpointConfig /// public bool Http2 { get; set; } + /// + /// Set if the endpoint requires HTTP Digest Authentication (Cryptonote coins) + /// + public bool DigestAuth { get; set; } + /// /// Optional endpoint category /// diff --git a/src/Miningcore/DaemonInterface/DaemonClient.cs b/src/Miningcore/DaemonInterface/DaemonClient.cs index ec5d715b7..f086a005a 100644 --- a/src/Miningcore/DaemonInterface/DaemonClient.cs +++ b/src/Miningcore/DaemonInterface/DaemonClient.cs @@ -73,9 +73,19 @@ public DaemonClient(JsonSerializerSettings serializerSettings, IMessageBus messa private readonly JsonSerializerSettings serializerSettings; protected DaemonEndpointConfig[] endPoints; - private HttpClient httpClient; + private Dictionary httpClients; private readonly JsonSerializer serializer; + private static readonly HttpClient defaultHttpClient = new HttpClient(new SocketsHttpHandler + { + AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, + + SslOptions = new SslClientAuthenticationOptions + { + RemoteCertificateValidationCallback = ((sender, certificate, chain, errors) => true), + } + }); + // Telemetry private readonly IMessageBus messageBus; @@ -96,14 +106,24 @@ public void Configure(DaemonEndpointConfig[] endPoints, string digestAuthRealm = this.endPoints = endPoints; - httpClient = new HttpClient(new SocketsHttpHandler + // create one HttpClient instance per endpoint that carries the associated credentials + httpClients = endPoints.ToDictionary(endpoint => endpoint, endpoint => { - AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, + if (string.IsNullOrEmpty(endpoint.User) || !endpoint.DigestAuth) + return defaultHttpClient; - SslOptions = new SslClientAuthenticationOptions + return new HttpClient(new SocketsHttpHandler { - RemoteCertificateValidationCallback = ((sender, certificate, chain, errors) => true), - } + AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, + + Credentials = new NetworkCredential(endpoint.User, endpoint.Password), + PreAuthenticate = true, + + SslOptions = new SslClientAuthenticationOptions + { + RemoteCertificateValidationCallback = ((sender, certificate, chain, errors) => true), + } + }); }); } @@ -327,7 +347,7 @@ private async Task BuildRequestTask(ILogger logger, DaemonEndpo request.Content = new StringContent(json, Encoding.UTF8, "application/json"); // build auth header - if (!string.IsNullOrEmpty(endPoint.User)) + if (!string.IsNullOrEmpty(endPoint.User) && !endPoint.DigestAuth) { var auth = $"{endPoint.User}:{endPoint.Password}"; var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(auth)); @@ -337,7 +357,7 @@ private async Task BuildRequestTask(ILogger logger, DaemonEndpo logger.Trace(() => $"Sending RPC request to {requestUrl}: {json}"); // send request - using (var response = await httpClient.SendAsync(request, ct)) + using (var response = await httpClients[endPoint].SendAsync(request, ct)) { // read response var responseContent = await response.Content.ReadAsStringAsync(); @@ -385,7 +405,7 @@ private async Task[]> BuildBatchRequestTask(ILogger logg request.Content = new StringContent(json, Encoding.UTF8, "application/json"); // build auth header - if (!string.IsNullOrEmpty(endPoint.User)) + if (!string.IsNullOrEmpty(endPoint.User) && !endPoint.DigestAuth) { var auth = $"{endPoint.User}:{endPoint.Password}"; var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(auth)); @@ -395,7 +415,7 @@ private async Task[]> BuildBatchRequestTask(ILogger logg logger.Trace(() => $"Sending RPC request to {requestUrl}: {json}"); // send request - using(var response = await httpClient.SendAsync(request)) + using(var response = await httpClients[endPoint].SendAsync(request)) { // deserialize response var jsonResponse = await response.Content.ReadAsStringAsync(); @@ -505,7 +525,6 @@ private IObservable WebsocketSubscribeEndpoint(ILogger logger, DaemonEnd // connect var protocol = conf.Ssl ? "wss" : "ws"; var uri = new Uri($"{protocol}://{endPoint.Host}:{conf.Port}{conf.HttpPath}"); - client.Options.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; logger.Debug(() => $"Establishing WebSocket connection to {uri}"); diff --git a/src/Miningcore/Payments/PayoutManager.cs b/src/Miningcore/Payments/PayoutManager.cs index 5bbc880b0..357bd33d7 100644 --- a/src/Miningcore/Payments/PayoutManager.cs +++ b/src/Miningcore/Payments/PayoutManager.cs @@ -21,6 +21,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Autofac; @@ -104,7 +105,21 @@ private async Task ProcessPoolsAsync() logger.Error(ex.InnerException ?? ex, () => $"[{pool.Id}] Payment processing failed"); } - catch(Exception ex) + catch (AggregateException ex) + { + switch (ex.InnerException) + { + case HttpRequestException httpEx: + logger.Error(() => $"[{pool.Id}] Payment processing failed: {httpEx.Message}"); + break; + + default: + logger.Error(ex.InnerException, () => $"[{pool.Id}] Payment processing failed"); + break; + } + } + + catch (Exception ex) { logger.Error(ex, () => $"[{pool.Id}] Payment processing failed"); } From bb811824f7c6082f3cb480d2a2a99292d41536f7 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sun, 11 Nov 2018 10:45:09 +0100 Subject: [PATCH 046/178] Refactor --- .../Blockchain/Bitcoin/BitcoinJobManager.cs | 2 +- .../Cryptonote/CryptonoteJobManager.cs | 2 +- .../Blockchain/Equihash/EquihashJobManager.cs | 2 +- .../Blockchain/Ethereum/EthereumJobManager.cs | 2 +- .../Extensions/MessageBusExtensions.cs | 49 ++++++++++++++++-- src/Miningcore/Mining/ShareRecorder.cs | 2 +- .../Messages/BlockNotification.cs | 51 +------------------ 7 files changed, 51 insertions(+), 59 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index 046ccd851..e5e06e857 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -111,7 +111,7 @@ private BitcoinJob CreateJob() blockTemplate.Height > job.BlockTemplate?.Height); if(isNew) - messageBus.SendMessage(new NewChainHeightNotification(poolConfig.Id, blockTemplate.Height, coin.Symbol)); + messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); if (isNew || forceUpdate) { diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs index b2fb8816e..e9d65626e 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs @@ -103,7 +103,7 @@ protected async Task UpdateJob(string via = null, string json = null) if (isNew) { - messageBus.SendMessage(new NewChainHeightNotification(poolConfig.Id, blockTemplate.Height, poolConfig.Template.Symbol)); + messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); if (via != null) logger.Info(() => $"Detected new block {blockTemplate.Height} via {via}"); diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index b12bc1e38..bcfd8926e 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -136,7 +136,7 @@ private EquihashJob CreateJob() blockTemplate.Height > job.BlockTemplate?.Height); if (isNew) - messageBus.SendMessage(new NewChainHeightNotification(poolConfig.Id, blockTemplate.Height, coin.Symbol)); + messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); if (isNew || forceUpdate) { diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs index 43a1f9fb1..33abbf7ed 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs @@ -125,7 +125,7 @@ protected bool UpdateJob(EthereumBlockTemplate blockTemplate) if (isNew) { - messageBus.SendMessage(new NewChainHeightNotification(poolConfig.Id, blockTemplate.Height, poolConfig.Template.Symbol)); + messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); var jobId = NextJobId("x8"); diff --git a/src/Miningcore/Extensions/MessageBusExtensions.cs b/src/Miningcore/Extensions/MessageBusExtensions.cs index 0eae4a389..50db41bfb 100644 --- a/src/Miningcore/Extensions/MessageBusExtensions.cs +++ b/src/Miningcore/Extensions/MessageBusExtensions.cs @@ -9,14 +9,33 @@ namespace Miningcore.Extensions { public static class MessageBusExtensions { - public static void NotifyBlockFound(this IMessageBus messageBus, string poolId, ulong blockHeight, string symbol) + public static void NotifyBlockFound(this IMessageBus messageBus, string poolId, Block block, CoinTemplate coin) { - messageBus.SendMessage(new BlockFoundNotification(poolId, blockHeight, symbol)); + // miner account explorer link + string minerExplorerLink = null; + + if (!string.IsNullOrEmpty(coin.ExplorerAccountLink)) + minerExplorerLink = string.Format(coin.ExplorerAccountLink, block.Miner); + + messageBus.SendMessage(new BlockFoundNotification + { + PoolId = poolId, + BlockHeight = block.BlockHeight, + Symbol = coin.Symbol, + Miner = block.Miner, + MinerExplorerLink = minerExplorerLink, + }); } public static void NotifyBlockConfirmationProgress(this IMessageBus messageBus, string poolId, Block block, CoinTemplate coin) { - messageBus.SendMessage(new BlockConfirmationProgressNotification(block.ConfirmationProgress, poolId, block.BlockHeight, coin.Symbol)); + messageBus.SendMessage(new BlockConfirmationProgressNotification + { + PoolId = poolId, + BlockHeight = block.BlockHeight, + Symbol = coin.Symbol, + Progress = block.ConfirmationProgress, + }); } public static void NotifyBlockUnlocked(this IMessageBus messageBus, string poolId, Block block, CoinTemplate coin) @@ -41,8 +60,28 @@ public static void NotifyBlockUnlocked(this IMessageBus messageBus, string poolI minerExplorerLink = string.Format(coin.ExplorerAccountLink, block.Miner); } - messageBus.SendMessage(new BlockUnlockedNotification(block.Status, poolId, - block.BlockHeight, block.Hash, block.Miner, minerExplorerLink, coin.Symbol, blockExplorerLink, block.Type)); + messageBus.SendMessage(new BlockUnlockedNotification + { + PoolId = poolId, + BlockHeight = block.BlockHeight, + BlockType = block.Type, + Symbol = coin.Symbol, + Status = block.Status, + BlockHash = block.Hash, + ExplorerLink = blockExplorerLink, + Miner = block.Miner, + MinerExplorerLink = minerExplorerLink, + }); + } + + public static void NotifyChainHeight(this IMessageBus messageBus, string poolId, ulong height, CoinTemplate coin) + { + messageBus.SendMessage(new NewChainHeightNotification + { + PoolId = poolId, + BlockHeight = height, + Symbol = coin.Symbol, + }); } } } diff --git a/src/Miningcore/Mining/ShareRecorder.cs b/src/Miningcore/Mining/ShareRecorder.cs index e848f9243..613846a10 100644 --- a/src/Miningcore/Mining/ShareRecorder.cs +++ b/src/Miningcore/Mining/ShareRecorder.cs @@ -122,7 +122,7 @@ await cf.RunTx(async (con, tx) => blockEntity.Status = BlockStatus.Pending; await blockRepo.InsertAsync(con, tx, blockEntity); - messageBus.NotifyBlockFound(share.PoolId, (ulong) share.BlockHeight, pools[share.PoolId].Template.Symbol); + messageBus.NotifyBlockFound(share.PoolId, blockEntity, pools[share.PoolId].Template); } }); } diff --git a/src/Miningcore/Notifications/Messages/BlockNotification.cs b/src/Miningcore/Notifications/Messages/BlockNotification.cs index d4fe7442b..14c29aa28 100644 --- a/src/Miningcore/Notifications/Messages/BlockNotification.cs +++ b/src/Miningcore/Notifications/Messages/BlockNotification.cs @@ -4,17 +4,6 @@ namespace Miningcore.Notifications.Messages { public abstract class BlockNotification { - protected BlockNotification(string poolId, ulong blockHeight, string symbol) - { - PoolId = poolId; - BlockHeight = blockHeight; - Symbol = symbol; - } - - protected BlockNotification() - { - } - public string PoolId { get; set; } public ulong BlockHeight { get; set; } public string Symbol { get; set; } @@ -22,57 +11,21 @@ protected BlockNotification() public class BlockFoundNotification : BlockNotification { - public BlockFoundNotification(string poolId, ulong blockHeight, string symbol) : base(poolId, blockHeight, symbol) - { - } - - public BlockFoundNotification() - { - } + public string Miner { get; set; } + public string MinerExplorerLink { get; set; } } public class NewChainHeightNotification : BlockNotification { - public NewChainHeightNotification(string poolId, ulong blockHeight, string symbol) : base(poolId, blockHeight, symbol) - { - } - - public NewChainHeightNotification() - { - } } public class BlockConfirmationProgressNotification : BlockNotification { - public BlockConfirmationProgressNotification(double progress, string poolId, ulong blockHeight, string symbol) : base(poolId, blockHeight, symbol) - { - Progress = progress; - } - - public BlockConfirmationProgressNotification() - { - } - public double Progress { get; set; } } public class BlockUnlockedNotification : BlockNotification { - public BlockUnlockedNotification(BlockStatus status, string poolId, ulong blockHeight, string blockHash, - string miner, string minerExplorerLink, string symbol, string explorerLink, string blockType = "block") : - base(poolId, blockHeight, symbol) - { - Status = status; - BlockType = blockType; - BlockHash = blockHash; - Miner = miner; - ExplorerLink = explorerLink; - } - - public BlockUnlockedNotification() - { - } - public BlockStatus Status { get; set; } public string BlockType { get; set; } public string BlockHash { get; set; } From 6263dfdc858eed61e0e765cb2de94599975df038 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sun, 11 Nov 2018 12:16:08 +0100 Subject: [PATCH 047/178] Hashrate updated notification --- .../WebSocketNotifications/NotificationType.cs | 3 ++- .../WebSocketNotificationsRelay.cs | 1 + src/Miningcore/Extensions/MessageBusExtensions.cs | 11 +++++++++++ src/Miningcore/Mining/StatsRecorder.cs | 15 ++++++++++++--- .../Messages/HashrateNotification.cs | 12 ++++++++++++ 5 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 src/Miningcore/Notifications/Messages/HashrateNotification.cs diff --git a/src/Miningcore/Api/WebSocketNotifications/NotificationType.cs b/src/Miningcore/Api/WebSocketNotifications/NotificationType.cs index 4a198c161..4613655ab 100644 --- a/src/Miningcore/Api/WebSocketNotifications/NotificationType.cs +++ b/src/Miningcore/Api/WebSocketNotifications/NotificationType.cs @@ -11,6 +11,7 @@ public enum WsNotificationType NewChainHeight, Payment, BlockUnlocked, - BlockUnlockProgress + BlockUnlockProgress, + HashrateUpdated } } diff --git a/src/Miningcore/Api/WebSocketNotifications/WebSocketNotificationsRelay.cs b/src/Miningcore/Api/WebSocketNotifications/WebSocketNotificationsRelay.cs index 3a48fdacf..b6d2266ba 100644 --- a/src/Miningcore/Api/WebSocketNotifications/WebSocketNotificationsRelay.cs +++ b/src/Miningcore/Api/WebSocketNotifications/WebSocketNotificationsRelay.cs @@ -38,6 +38,7 @@ public WebSocketNotificationsRelay(WebSocketConnectionManager webSocketConnectio Relay(WsNotificationType.BlockUnlockProgress); Relay(WsNotificationType.NewChainHeight); Relay(WsNotificationType.Payment); + Relay(WsNotificationType.HashrateUpdated); } private IMessageBus messageBus; diff --git a/src/Miningcore/Extensions/MessageBusExtensions.cs b/src/Miningcore/Extensions/MessageBusExtensions.cs index 50db41bfb..01d106707 100644 --- a/src/Miningcore/Extensions/MessageBusExtensions.cs +++ b/src/Miningcore/Extensions/MessageBusExtensions.cs @@ -83,5 +83,16 @@ public static void NotifyChainHeight(this IMessageBus messageBus, string poolId, Symbol = coin.Symbol, }); } + + public static void NotifyHashrateUpdated(this IMessageBus messageBus, string poolId, double hashrate, string miner = null, string worker = null) + { + messageBus.SendMessage(new HashrateNotification + { + PoolId = poolId, + Hashrate = hashrate, + Miner = miner, + Worker = worker, + }); + } } } diff --git a/src/Miningcore/Mining/StatsRecorder.cs b/src/Miningcore/Mining/StatsRecorder.cs index 91247b0ab..9746a2c26 100644 --- a/src/Miningcore/Mining/StatsRecorder.cs +++ b/src/Miningcore/Mining/StatsRecorder.cs @@ -11,6 +11,7 @@ using Miningcore.Configuration; using Miningcore.Contracts; using Miningcore.Extensions; +using Miningcore.Messaging; using Miningcore.Persistence; using Miningcore.Persistence.Model; using Miningcore.Persistence.Repositories; @@ -25,13 +26,15 @@ public class StatsRecorder public StatsRecorder(IComponentContext ctx, IMasterClock clock, IConnectionFactory cf, + IMessageBus messageBus, IMapper mapper, IShareRepository shareRepo, IStatsRepository statsRepo) { Contract.RequiresNonNull(ctx, nameof(ctx)); Contract.RequiresNonNull(clock, nameof(clock)); - Contract.RequiresNonNull(cf, nameof(cf)); + Contract.RequiresNonNull(cf, nameof(cf)); + Contract.RequiresNonNull(messageBus, nameof(messageBus)); Contract.RequiresNonNull(mapper, nameof(mapper)); Contract.RequiresNonNull(shareRepo, nameof(shareRepo)); Contract.RequiresNonNull(statsRepo, nameof(statsRepo)); @@ -40,6 +43,7 @@ public StatsRecorder(IComponentContext ctx, this.clock = clock; this.cf = cf; this.mapper = mapper; + this.messageBus = messageBus; this.shareRepo = shareRepo; this.statsRepo = statsRepo; @@ -50,6 +54,7 @@ public StatsRecorder(IComponentContext ctx, private readonly IStatsRepository statsRepo; private readonly IConnectionFactory cf; private readonly IMapper mapper; + private readonly IMessageBus messageBus; private readonly IComponentContext ctx; private readonly IShareRepository shareRepo; private readonly AutoResetEvent stopEvent = new AutoResetEvent(false); @@ -163,6 +168,8 @@ private async Task UpdatePoolHashratesAsync() pool.PoolStats.ConnectedMiners = byMiner.Length; pool.PoolStats.PoolHashrate = (ulong) Math.Ceiling(poolHashrate); pool.PoolStats.SharesPerSecond = (int) (poolHashesCountAccumulated / windowActual); + + messageBus.NotifyHashrateUpdated(pool.Config.Id, poolHashrate); } } @@ -203,10 +210,12 @@ await cf.RunTx(async (con, tx) => // update stats.Hashrate = hashrate; stats.Worker = item.Worker; - stats.SharesPerSecond = (double) item.Count / windowActual; - + stats.SharesPerSecond = (double) item.Count / windowActual; + // persist await statsRepo.InsertMinerWorkerPerformanceStatsAsync(con, tx, stats); + + messageBus.NotifyHashrateUpdated(pool.Config.Id, hashrate, stats.Miner, item.Worker); } } }); diff --git a/src/Miningcore/Notifications/Messages/HashrateNotification.cs b/src/Miningcore/Notifications/Messages/HashrateNotification.cs new file mode 100644 index 000000000..0ebde883f --- /dev/null +++ b/src/Miningcore/Notifications/Messages/HashrateNotification.cs @@ -0,0 +1,12 @@ +using Miningcore.Persistence.Model; + +namespace Miningcore.Notifications.Messages +{ + public class HashrateNotification + { + public string PoolId { get; set; } + public double Hashrate { get; set; } + public string Miner { get; set; } + public string Worker { get; set; } + } +} From bc4914589a35a6fcfbe2815e21032067e6de1501 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sun, 11 Nov 2018 12:27:03 +0100 Subject: [PATCH 048/178] More block notification properties --- src/Miningcore/Extensions/MessageBusExtensions.cs | 2 ++ src/Miningcore/Notifications/Messages/BlockNotification.cs | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/Miningcore/Extensions/MessageBusExtensions.cs b/src/Miningcore/Extensions/MessageBusExtensions.cs index 01d106707..6b327fa2b 100644 --- a/src/Miningcore/Extensions/MessageBusExtensions.cs +++ b/src/Miningcore/Extensions/MessageBusExtensions.cs @@ -24,6 +24,7 @@ public static void NotifyBlockFound(this IMessageBus messageBus, string poolId, Symbol = coin.Symbol, Miner = block.Miner, MinerExplorerLink = minerExplorerLink, + Source = block.Source, }); } @@ -66,6 +67,7 @@ public static void NotifyBlockUnlocked(this IMessageBus messageBus, string poolI BlockHeight = block.BlockHeight, BlockType = block.Type, Symbol = coin.Symbol, + Reward = block.Reward, Status = block.Status, BlockHash = block.Hash, ExplorerLink = blockExplorerLink, diff --git a/src/Miningcore/Notifications/Messages/BlockNotification.cs b/src/Miningcore/Notifications/Messages/BlockNotification.cs index 14c29aa28..058d9e57a 100644 --- a/src/Miningcore/Notifications/Messages/BlockNotification.cs +++ b/src/Miningcore/Notifications/Messages/BlockNotification.cs @@ -1,4 +1,6 @@ using Miningcore.Persistence.Model; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; namespace Miningcore.Notifications.Messages { @@ -13,6 +15,7 @@ public class BlockFoundNotification : BlockNotification { public string Miner { get; set; } public string MinerExplorerLink { get; set; } + public string Source { get; set; } } public class NewChainHeightNotification : BlockNotification @@ -26,9 +29,12 @@ public class BlockConfirmationProgressNotification : BlockNotification public class BlockUnlockedNotification : BlockNotification { + [JsonConverter(typeof(StringEnumConverter))] public BlockStatus Status { get; set; } + public string BlockType { get; set; } public string BlockHash { get; set; } + public decimal Reward { get; set; } public string Miner { get; set; } public string ExplorerLink { get; set; } public string MinerExplorerLink { get; set; } From 3162839f9c8b277cef8940a8d2fd23be78e790b3 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 12 Nov 2018 15:19:06 +0100 Subject: [PATCH 049/178] Emit HashrateNotification for miner's total hashrate --- src/Miningcore/Mining/StatsRecorder.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Miningcore/Mining/StatsRecorder.cs b/src/Miningcore/Mining/StatsRecorder.cs index 9746a2c26..5671b46cb 100644 --- a/src/Miningcore/Mining/StatsRecorder.cs +++ b/src/Miningcore/Mining/StatsRecorder.cs @@ -197,6 +197,7 @@ await cf.RunTx(async (con, tx) => await cf.RunTx(async (con, tx) => { stats.Miner = minerHashes.Key; + double minerTotalHashrate = 0; foreach(var item in minerHashes) { @@ -206,6 +207,7 @@ await cf.RunTx(async (con, tx) => if (windowActual >= MinHashrateCalculationWindow) { var hashrate = pool.HashrateFromShares(item.Sum, windowActual) * HashrateBoostFactor; + minerTotalHashrate += hashrate; // update stats.Hashrate = hashrate; @@ -217,7 +219,9 @@ await cf.RunTx(async (con, tx) => messageBus.NotifyHashrateUpdated(pool.Config.Id, hashrate, stats.Miner, item.Worker); } - } + } + + messageBus.NotifyHashrateUpdated(pool.Config.Id, minerTotalHashrate, stats.Miner, null); }); } } From 7fbf718a0c58c1678c3f212794d245d62ef69de6 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 12 Nov 2018 15:19:50 +0100 Subject: [PATCH 050/178] WIP --- src/Miningcore/Mining/StatsRecorder.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Miningcore/Mining/StatsRecorder.cs b/src/Miningcore/Mining/StatsRecorder.cs index 5671b46cb..b92c1d56d 100644 --- a/src/Miningcore/Mining/StatsRecorder.cs +++ b/src/Miningcore/Mining/StatsRecorder.cs @@ -193,11 +193,12 @@ await cf.RunTx(async (con, tx) => // calculate & update miner, worker hashrates foreach(var minerHashes in byMiner) - { + { + double minerTotalHashrate = 0; + await cf.RunTx(async (con, tx) => { stats.Miner = minerHashes.Key; - double minerTotalHashrate = 0; foreach(var item in minerHashes) { @@ -220,9 +221,9 @@ await cf.RunTx(async (con, tx) => messageBus.NotifyHashrateUpdated(pool.Config.Id, hashrate, stats.Miner, item.Worker); } } + }); - messageBus.NotifyHashrateUpdated(pool.Config.Id, minerTotalHashrate, stats.Miner, null); - }); + messageBus.NotifyHashrateUpdated(pool.Config.Id, minerTotalHashrate, stats.Miner, null); } } } From 916710e98710b8e915c95646e62e42f91672803c Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 12 Nov 2018 20:19:03 +0100 Subject: [PATCH 051/178] Publish block effort --- src/Miningcore/Extensions/MessageBusExtensions.cs | 2 ++ src/Miningcore/Notifications/Messages/BlockNotification.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Miningcore/Extensions/MessageBusExtensions.cs b/src/Miningcore/Extensions/MessageBusExtensions.cs index 6b327fa2b..04d340eaa 100644 --- a/src/Miningcore/Extensions/MessageBusExtensions.cs +++ b/src/Miningcore/Extensions/MessageBusExtensions.cs @@ -35,6 +35,7 @@ public static void NotifyBlockConfirmationProgress(this IMessageBus messageBus, PoolId = poolId, BlockHeight = block.BlockHeight, Symbol = coin.Symbol, + Effort = block.Effort, Progress = block.ConfirmationProgress, }); } @@ -69,6 +70,7 @@ public static void NotifyBlockUnlocked(this IMessageBus messageBus, string poolI Symbol = coin.Symbol, Reward = block.Reward, Status = block.Status, + Effort = block.Effort, BlockHash = block.Hash, ExplorerLink = blockExplorerLink, Miner = block.Miner, diff --git a/src/Miningcore/Notifications/Messages/BlockNotification.cs b/src/Miningcore/Notifications/Messages/BlockNotification.cs index 058d9e57a..c9fe8f84a 100644 --- a/src/Miningcore/Notifications/Messages/BlockNotification.cs +++ b/src/Miningcore/Notifications/Messages/BlockNotification.cs @@ -25,6 +25,7 @@ public class NewChainHeightNotification : BlockNotification public class BlockConfirmationProgressNotification : BlockNotification { public double Progress { get; set; } + public double? Effort { get; set; } } public class BlockUnlockedNotification : BlockNotification @@ -35,6 +36,7 @@ public class BlockUnlockedNotification : BlockNotification public string BlockType { get; set; } public string BlockHash { get; set; } public decimal Reward { get; set; } + public double? Effort { get; set; } public string Miner { get; set; } public string ExplorerLink { get; set; } public string MinerExplorerLink { get; set; } From fa76f380b3bbf97001881f955b5ff9c38f26c536 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 13 Nov 2018 08:38:56 +0100 Subject: [PATCH 052/178] Camelcase enum serialization --- src/Miningcore/Configuration/ClusterConfig.cs | 12 ++++++------ .../Notifications/Messages/BlockNotification.cs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index 9ceb01fb2..f1dc83aed 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -63,7 +63,7 @@ public abstract partial class CoinTemplate /// /// Family /// - [JsonConverter(typeof(StringEnumConverter))] + [JsonConverter(typeof(StringEnumConverter), true)] [JsonProperty(Order = -8)] public CoinFamily Family { get; set; } @@ -118,7 +118,7 @@ public partial class BitcoinTemplate : CoinTemplate { [JsonProperty(Order = -7, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] [DefaultValue(BitcoinSubfamily.None)] - [JsonConverter(typeof(StringEnumConverter))] + [JsonConverter(typeof(StringEnumConverter), true)] public BitcoinSubfamily Subfamily { get; set; } public JObject CoinbaseHasher { get; set; } @@ -211,7 +211,7 @@ public partial class EquihashNetworkParams [JsonProperty(Order = -7, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] [DefaultValue(EquihashSubfamily.None)] - [JsonConverter(typeof(StringEnumConverter))] + [JsonConverter(typeof(StringEnumConverter), true)] public EquihashSubfamily Subfamily { get; set; } public Dictionary Networks { get; set; } @@ -245,13 +245,13 @@ public partial class CryptonoteCoinTemplate : CoinTemplate { [JsonProperty(Order = -7, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] [DefaultValue(CryptonoteSubfamily.None)] - [JsonConverter(typeof(StringEnumConverter))] + [JsonConverter(typeof(StringEnumConverter), true)] public CryptonoteSubfamily Subfamily { get; set; } /// /// Broader Cryptonight hash family /// - [JsonConverter(typeof(StringEnumConverter))] + [JsonConverter(typeof(StringEnumConverter), true)] [JsonProperty(Order = -5)] public CryptonightHashType Hash { get; set; } @@ -308,7 +308,7 @@ public partial class EthereumCoinTemplate : CoinTemplate { [JsonProperty(Order = -7, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] [DefaultValue(EthereumSubfamily.None)] - [JsonConverter(typeof(StringEnumConverter))] + [JsonConverter(typeof(StringEnumConverter), true)] public EthereumSubfamily Subfamily { get; set; } } diff --git a/src/Miningcore/Notifications/Messages/BlockNotification.cs b/src/Miningcore/Notifications/Messages/BlockNotification.cs index c9fe8f84a..bb63a2673 100644 --- a/src/Miningcore/Notifications/Messages/BlockNotification.cs +++ b/src/Miningcore/Notifications/Messages/BlockNotification.cs @@ -30,7 +30,7 @@ public class BlockConfirmationProgressNotification : BlockNotification public class BlockUnlockedNotification : BlockNotification { - [JsonConverter(typeof(StringEnumConverter))] + [JsonConverter(typeof(StringEnumConverter), true)] public BlockStatus Status { get; set; } public string BlockType { get; set; } From 42543fde254a6962e78f316e671e5ea898d16afe Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 13 Nov 2018 11:31:46 +0100 Subject: [PATCH 053/178] Don't clear validJobs on new blocks, causing lots of rejects --- .../Blockchain/Bitcoin/BitcoinJobManager.cs | 13 ++++--------- .../Cryptonote/CryptonoteWorkerContext.cs | 4 ++-- .../Blockchain/Equihash/EquihashJobManager.cs | 13 ++++--------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index e5e06e857..37ba72ee5 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -131,8 +131,6 @@ private BitcoinJob CreateJob() else logger.Info(() => $"Detected new block {blockTemplate.Height}"); - validJobs.Clear(); - // update stats BlockchainStats.LastNetworkBlockTime = clock.Now; BlockchainStats.BlockHeight = blockTemplate.Height; @@ -141,14 +139,11 @@ private BitcoinJob CreateJob() BlockchainStats.NextNetworkBits = blockTemplate.Bits; } - else - { - // trim active jobs - while (validJobs.Count > maxActiveJobs - 1) - validJobs.RemoveAt(0); - } + validJobs.Insert(0, job); - validJobs.Add(job); + // trim active jobs + while (validJobs.Count > maxActiveJobs) + validJobs.RemoveAt(validJobs.Count - 1); } currentJob = job; diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteWorkerContext.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteWorkerContext.cs index ed5e33450..479315021 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteWorkerContext.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteWorkerContext.cs @@ -41,10 +41,10 @@ public class CryptonoteWorkerContext : WorkerContextBase public void AddJob(CryptonoteWorkerJob job) { - validJobs.Add(job); + validJobs.Insert(0, job); while(validJobs.Count > 4) - validJobs.RemoveAt(0); + validJobs.RemoveAt(validJobs.Count - 1); } public CryptonoteWorkerJob FindJob(string jobId) diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index bcfd8926e..eea887391 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -155,8 +155,6 @@ private EquihashJob CreateJob() else logger.Info(() => $"Detected new block {blockTemplate.Height}"); - validJobs.Clear(); - // update stats BlockchainStats.LastNetworkBlockTime = clock.Now; BlockchainStats.BlockHeight = blockTemplate.Height; @@ -165,14 +163,11 @@ private EquihashJob CreateJob() BlockchainStats.NextNetworkBits = blockTemplate.Bits; } - else - { - // trim active jobs - while (validJobs.Count > maxActiveJobs - 1) - validJobs.RemoveAt(0); - } + validJobs.Insert(0, job); - validJobs.Add(job); + // trim active jobs + while (validJobs.Count > maxActiveJobs) + validJobs.RemoveAt(validJobs.Count - 1); } currentJob = job; From 3fc7a8aede297b37e52fc82932cfe13f2be45382 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 13 Nov 2018 14:07:35 +0100 Subject: [PATCH 054/178] Implement support for mining.extranonce.subscribe --- .../Blockchain/Bitcoin/BitcoinJobTests.cs | 4 +- .../Blockchain/Bitcoin/BitcoinJob.cs | 23 ++++++----- .../Blockchain/Bitcoin/BitcoinJobManager.cs | 8 ++-- .../Bitcoin/BitcoinJobManagerBase.cs | 4 +- .../Blockchain/Bitcoin/BitcoinPool.cs | 40 +++++++++++++++---- .../Bitcoin/BitcoinStratumMethods.cs | 5 +++ .../Bitcoin/BitcoinWorkerContext.cs | 5 +++ .../Blockchain/Equihash/EquihashJobManager.cs | 6 +-- .../Blockchain/Equihash/EquihashPool.cs | 4 +- .../Blockchain/ExtraNonceProviderBase.cs | 2 +- 10 files changed, 69 insertions(+), 32 deletions(-) diff --git a/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs b/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs index 1e378da14..1ba880b43 100644 --- a/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs +++ b/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs @@ -56,7 +56,7 @@ public void BitcoinJob_Should_Accept_Valid_Share() // set clock to submission time clock.CurrentTime = DateTimeOffset.FromUnixTimeSeconds(1508869907).UtcDateTime; - var (share, blockHex) = job.ProcessShare(worker, "01000000", "59ef86f2", "8d84ae6a"); + var (share, blockHex, nonceSpaceUsed) = job.ProcessShare(worker, "01000000", "59ef86f2", "8d84ae6a"); Assert.NotNull(share); Assert.True(share.IsBlockCandidate); @@ -95,7 +95,7 @@ public void BitcoinJob_Should_Not_Accept_Invalid_Share() Assert.Throws(() => job.ProcessShare(worker, "02000000", "59ef86f2", "8d84ae6a")); // make sure we don't accept case-sensitive duplicate shares as basically 0xdeadbeaf = 0xDEADBEAF. - var (share, blockHex) = job.ProcessShare(worker, "01000000", "59ef86f2", "8d84ae6a"); + var (share, blockHex, nonceSpaceUsed) = job.ProcessShare(worker, "01000000", "59ef86f2", "8d84ae6a"); Assert.Throws(() => job.ProcessShare(worker, "01000000", "59ef86f2", "8D84AE6A")); // invalid time diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs index 6faca522a..39aa440ef 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs @@ -309,7 +309,7 @@ protected byte[] SerializeHeader(Span coinbaseHash, uint nTime, uint nonce return blockHeader.ToBytes(); } - protected virtual (Share Share, string BlockHex) ProcessShareInternal( + protected virtual (Share Share, string BlockHex, double NonceSpaceUsed) ProcessShareInternal( StratumClient worker, string extraNonce2, uint nTime, uint nonce, uint? versionBits) { var context = worker.ContextAs(); @@ -360,6 +360,9 @@ protected virtual (Share Share, string BlockHex) ProcessShareInternal( Difficulty = stratumDifficulty / shareMultiplier, }; + // calculate used none-space + var nonceSpaceUsed = (double) nonce / (double) uint.MaxValue; + if (isBlockCandidate) { result.IsBlockCandidate = true; @@ -371,10 +374,10 @@ protected virtual (Share Share, string BlockHex) ProcessShareInternal( var blockBytes = SerializeBlock(headerBytes, coinbase); var blockHex = blockBytes.ToHexString(); - return (result, blockHex); + return (result, blockHex, nonceSpaceUsed); } - return (result, null); + return (result, null, nonceSpaceUsed); } protected virtual byte[] SerializeCoinbase(string extraNonce1, string extraNonce2) @@ -581,13 +584,13 @@ public object GetJobParams(bool isNew) return jobParams; } - public virtual (Share Share, string BlockHex) ProcessShare(StratumClient worker, - string extraNonce2, string nTime, string nonce, string versionBits = null) + public virtual (Share Share, string BlockHex, double NonceSpaceHeight) ProcessShare(StratumClient worker, + string extraNonce2, string nTime, string nonceString, string versionBits = null) { Contract.RequiresNonNull(worker, nameof(worker)); Contract.Requires(!string.IsNullOrEmpty(extraNonce2), $"{nameof(extraNonce2)} must not be empty"); Contract.Requires(!string.IsNullOrEmpty(nTime), $"{nameof(nTime)} must not be empty"); - Contract.Requires(!string.IsNullOrEmpty(nonce), $"{nameof(nonce)} must not be empty"); + Contract.Requires(!string.IsNullOrEmpty(nonceString), $"{nameof(nonceString)} must not be empty"); var context = worker.ContextAs(); @@ -600,10 +603,10 @@ public virtual (Share Share, string BlockHex) ProcessShare(StratumClient worker, throw new StratumException(StratumError.Other, "ntime out of range"); // validate nonce - if (nonce.Length != 8) + if (nonceString.Length != 8) throw new StratumException(StratumError.Other, "incorrect size of nonce"); - var nonceInt = uint.Parse(nonce, NumberStyles.HexNumber); + var nonce = uint.Parse(nonceString, NumberStyles.HexNumber); // validate version-bits (overt ASIC boost) uint versionBitsInt = 0; @@ -618,10 +621,10 @@ public virtual (Share Share, string BlockHex) ProcessShare(StratumClient worker, } // dupe check - if (!RegisterSubmit(context.ExtraNonce1, extraNonce2, nTime, nonce)) + if (!RegisterSubmit(context.ExtraNonce1, extraNonce2, nTime, nonceString)) throw new StratumException(StratumError.DuplicateShare, "duplicate share"); - return ProcessShareInternal(worker, extraNonce2, nTimeInt, nonceInt, versionBitsInt); + return ProcessShareInternal(worker, extraNonce2, nTimeInt, nonce, versionBitsInt); } #endregion // API-Surface diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index 37ba72ee5..313652e90 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -182,7 +182,7 @@ public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfi base.Configure(poolConfig, clusterConfig); } - public override object[] GetSubscriberData(StratumClient worker) + public override object[] UpdateSubscriberData(StratumClient worker) { Contract.RequiresNonNull(worker, nameof(worker)); @@ -201,7 +201,7 @@ public override object[] GetSubscriberData(StratumClient worker) return responseData; } - public override async ValueTask SubmitShareAsync(StratumClient worker, object submission, + public override async ValueTask<(Share Share, double NonceSpaceUsed)> SubmitShareAsync(StratumClient worker, object submission, double stratumDifficultyBase, CancellationToken ct) { Contract.RequiresNonNull(worker, nameof(worker)); @@ -241,7 +241,7 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob var workerName = split.Length > 1 ? split[1] : null; // validate & process - var (share, blockHex) = job.ProcessShare(worker, extraNonce2, nTime, nonce, versionBits); + var (share, blockHex, nonceSpaceUsed) = job.ProcessShare(worker, extraNonce2, nTime, nonce, versionBits); // enrich share with common data share.PoolId = poolConfig.Id; @@ -280,7 +280,7 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob } } - return share; + return (share, nonceSpaceUsed); } public double ShareMultiplier => coin.ShareMultiplier; diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index 2b36d3a9f..957197c38 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -630,9 +630,9 @@ public virtual async Task ValidateAddressAsync(string address, Cancellatio return result.Response != null && result.Response.IsValid; } - public abstract object[] GetSubscriberData(StratumClient worker); + public abstract object[] UpdateSubscriberData(StratumClient worker); - public abstract ValueTask SubmitShareAsync(StratumClient worker, object submission, + public abstract ValueTask<(Share Share, double NonceSpaceUsed)> SubmitShareAsync(StratumClient worker, object submission, double stratumDifficultyBase, CancellationToken ct); #endregion // API-Surface diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs index 8721ee463..7d27f6142 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs @@ -81,7 +81,7 @@ protected virtual async Task OnSubscribeAsync(StratumClient client, Timestamped< new object[] { BitcoinStratumMethods.MiningNotify, client.ConnectionId } } } - .Concat(manager.GetSubscriberData(client)) + .Concat(manager.UpdateSubscriberData(client)) .ToArray(); await client.RespondAsync(data, request.Id); @@ -187,7 +187,7 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped(); var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port]; - var share = await manager.SubmitShareAsync(client, requestParams, poolEndpoint.Difficulty, ct); + var (share, nonceSpaceUsed) = await manager.SubmitShareAsync(client, requestParams, poolEndpoint.Difficulty, ct); await client.RespondAsync(true, request.Id); @@ -206,6 +206,10 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped= 0.9) + await UpdateExtraNonceAsync(client, nonceSpaceUsed); } catch(StratumException ex) @@ -254,6 +258,17 @@ private async Task OnSuggestDifficultyAsync(StratumClient client, Timestamped tsRequest) + { + var request = tsRequest.Value; + var context = client.ContextAs(); + + context.HasExtraNonceSubscription = true; + + // acknowledge + await client.RespondAsync(true, request.Id); + } + private async Task OnConfigureMiningAsync(StratumClient client, Timestamped tsRequest) { var request = tsRequest.Value; @@ -366,13 +381,22 @@ protected virtual async Task OnNewJobAsync(object jobParams) } } + private async Task UpdateExtraNonceAsync(StratumClient client, double nonceSpaceUsed) + { + var parameters = manager.UpdateSubscriberData(client); + await client.NotifyAsync(BitcoinStratumMethods.SetExtraNonce, parameters); + + logger.Info(() => $"[{client.ConnectionId}] Assigned new extra-nonce {parameters[0]} at {(int)(nonceSpaceUsed * 100)}% NS"); + + // force work restart using new extra-nonce + await client.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + } + public override double HashrateFromShares(double shares, double interval) { var multiplier = BitcoinConstants.Pow2x32; var result = shares * multiplier / interval; - //result *= coin.HashrateMultiplier; - return result; } @@ -463,6 +487,10 @@ protected override async Task OnRequestAsync(StratumClient client, await OnSuggestDifficultyAsync(client, tsRequest); break; + case BitcoinStratumMethods.ExtraNonceSubscribe: + await OnExtraNonceSubscribeAsync(client, tsRequest); + break; + case BitcoinStratumMethods.MiningConfigure: await OnConfigureMiningAsync(client, tsRequest); // ignored @@ -472,10 +500,6 @@ protected override async Task OnRequestAsync(StratumClient client, // ignored break; - case BitcoinStratumMethods.ExtraNonceSubscribe: - // ignored - break; - case BitcoinStratumMethods.MiningMultiVersion: // ignored break; diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinStratumMethods.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinStratumMethods.cs index 99258feef..43e5a29dc 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinStratumMethods.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinStratumMethods.cs @@ -64,6 +64,11 @@ public class BitcoinStratumMethods /// public const string ExtraNonceSubscribe = "mining.extranonce.subscribe"; + /// + /// Used to signal the miner a newly assigned extraNonce + /// + public const string SetExtraNonce = "mining.set_extranonce"; + /// /// Appears to be a command sent by AntMiner devices for use with ASICBOOST. /// https://www.reddit.com/r/Bitcoin/comments/63yo27/some_circumstantial_evidence_supporting_the_claim/dfy5o65/ diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinWorkerContext.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinWorkerContext.cs index d316b8090..a6706c76b 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinWorkerContext.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinWorkerContext.cs @@ -36,6 +36,11 @@ public class BitcoinWorkerContext : WorkerContextBase public string ExtraNonce1 { get; set; } + /// + /// Client has requested on-the-fly changes for ExtraNonce1 + /// + public bool HasExtraNonceSubscription { get; internal set; } + /// /// Mask for version-rolling (Overt ASIC-Boost) /// diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index eea887391..bf4cb5ff3 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -214,7 +214,7 @@ public override async Task ValidateAddressAsync(string address, Cancellati return result.Response != null && result.Response.IsValid; } - public override object[] GetSubscriberData(StratumClient worker) + public override object[] UpdateSubscriberData(StratumClient worker) { Contract.RequiresNonNull(worker, nameof(worker)); @@ -232,7 +232,7 @@ public override object[] GetSubscriberData(StratumClient worker) return responseData; } - public override async ValueTask SubmitShareAsync(StratumClient worker, object submission, + public override async ValueTask<(Share Share, double NonceSpaceUsed)> SubmitShareAsync(StratumClient worker, object submission, double stratumDifficultyBase, CancellationToken ct) { Contract.RequiresNonNull(worker, nameof(worker)); @@ -315,7 +315,7 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob share.Difficulty = share.Difficulty; share.Created = clock.Now; - return share; + return (share, 0); } diff --git a/src/Miningcore/Blockchain/Equihash/EquihashPool.cs b/src/Miningcore/Blockchain/Equihash/EquihashPool.cs index 5e687e8ee..c9af38038 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashPool.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashPool.cs @@ -141,7 +141,7 @@ protected async Task OnSubscribeAsync(StratumClient client, Timestamped(); var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port]; - var share = await manager.SubmitShareAsync(client, requestParams, poolEndpoint.Difficulty, ct); + var (share, _) = await manager.SubmitShareAsync(client, requestParams, poolEndpoint.Difficulty, ct); await client.RespondAsync(true, request.Id); diff --git a/src/Miningcore/Blockchain/ExtraNonceProviderBase.cs b/src/Miningcore/Blockchain/ExtraNonceProviderBase.cs index 9cfcc36bf..0741e51ea 100644 --- a/src/Miningcore/Blockchain/ExtraNonceProviderBase.cs +++ b/src/Miningcore/Blockchain/ExtraNonceProviderBase.cs @@ -58,7 +58,7 @@ public string Next() { counter++; if (counter > nonceMax) - counter = 0; + counter = 1; // encode to hex var result = counter.ToString(stringFormat); From 895723ddc539893dbcf52fcc5f9de4144de1e932 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 13 Nov 2018 14:31:03 +0100 Subject: [PATCH 055/178] Also update extranonce if client subscribed for updates and submitted a duplicate share --- .../Blockchain/Bitcoin/BitcoinPool.cs | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs index 7d27f6142..0c12cf5a3 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs @@ -159,6 +159,7 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped(); + var updateExtraNonce = false; try { @@ -209,10 +210,13 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped= 0.9) - await UpdateExtraNonceAsync(client, nonceSpaceUsed); + { + logger.Info(() => $"[{client.ConnectionId}] Assigning new extra-nonce at {(int)(nonceSpaceUsed * 100)}% NS"); + updateExtraNonce = true; + } } - catch(StratumException ex) + catch (StratumException ex) { // telemetry PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, false); @@ -221,10 +225,27 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped $"[{client.ConnectionId}] Share rejected: {ex.Message}"); + // update extra-nonce + if (ex.Code == StratumError.DuplicateShare) + { + logger.Info(() => $"[{client.ConnectionId}] Assigning new extra-nonce on duplicate share"); + updateExtraNonce = true; + + // make sure submit is answered before updating extra-nonce + await client.RespondErrorAsync(ex.Code, ex.Message, request.Id, false); + } + // banning ConsiderBan(client, context, poolConfig.Banning); - throw; + if(!updateExtraNonce) + throw; + } + + finally + { + if (updateExtraNonce) + await UpdateExtraNonceAsync(client); } } @@ -381,13 +402,11 @@ protected virtual async Task OnNewJobAsync(object jobParams) } } - private async Task UpdateExtraNonceAsync(StratumClient client, double nonceSpaceUsed) + private async Task UpdateExtraNonceAsync(StratumClient client) { var parameters = manager.UpdateSubscriberData(client); await client.NotifyAsync(BitcoinStratumMethods.SetExtraNonce, parameters); - logger.Info(() => $"[{client.ConnectionId}] Assigned new extra-nonce {parameters[0]} at {(int)(nonceSpaceUsed * 100)}% NS"); - // force work restart using new extra-nonce await client.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); } From cdc62184f6d424b885fa113a33497b1137619200 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 13 Nov 2018 14:32:42 +0100 Subject: [PATCH 056/178] Update range --- src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs index 0c12cf5a3..3e2605cc4 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs @@ -209,7 +209,7 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped= 0.9) + if (!share.IsBlockCandidate && context.HasExtraNonceSubscription && nonceSpaceUsed >= 0.95) { logger.Info(() => $"[{client.ConnectionId}] Assigning new extra-nonce at {(int)(nonceSpaceUsed * 100)}% NS"); updateExtraNonce = true; From e07c9727e45fe291d1224c6087c7c9095a1dba03 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 13 Nov 2018 16:18:35 +0100 Subject: [PATCH 057/178] WIP --- src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs index 3e2605cc4..a289b25ce 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs @@ -194,10 +194,6 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped $"[{client.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty * coin.ShareMultiplier, 3)}"); // update pool stats @@ -214,6 +210,9 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped $"[{client.ConnectionId}] Assigning new extra-nonce at {(int)(nonceSpaceUsed * 100)}% NS"); updateExtraNonce = true; } + + // telemetry + PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, true); } catch (StratumException ex) From efafcf4acbb03460dd07a6cb4de0e3c49ddcb208 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 13 Nov 2018 18:05:36 +0100 Subject: [PATCH 058/178] Fix rounding problems with Bitcoin Core 0.17 --- src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs index 1258e5d14..b5ee06991 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs @@ -212,7 +212,7 @@ public virtual async Task PayoutAsync(Balance[] balances) // build args var amounts = balances .Where(x => x.Amount > 0) - .ToDictionary(x => x.Address, x => Math.Round(x.Amount, 8)); + .ToDictionary(x => x.Address, x => Math.Round(x.Amount, 4)); if (amounts.Count == 0) return; From 372295069d7a88cb09ec75352aeddef6326f59e6 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 13 Nov 2018 18:32:05 +0100 Subject: [PATCH 059/178] Revert "Implement support for mining.extranonce.subscribe" This reverts commit 3fc7a8aede297b37e52fc82932cfe13f2be45382. --- .../Blockchain/Bitcoin/BitcoinJobTests.cs | 4 +- .../Blockchain/Bitcoin/BitcoinJob.cs | 23 +++--- .../Blockchain/Bitcoin/BitcoinJobManager.cs | 8 +-- .../Bitcoin/BitcoinJobManagerBase.cs | 4 +- .../Blockchain/Bitcoin/BitcoinPool.cs | 70 ++++--------------- .../Bitcoin/BitcoinStratumMethods.cs | 5 -- .../Bitcoin/BitcoinWorkerContext.cs | 5 -- .../Blockchain/Equihash/EquihashJobManager.cs | 6 +- .../Blockchain/Equihash/EquihashPool.cs | 4 +- .../Blockchain/ExtraNonceProviderBase.cs | 2 +- 10 files changed, 38 insertions(+), 93 deletions(-) diff --git a/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs b/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs index 1ba880b43..1e378da14 100644 --- a/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs +++ b/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs @@ -56,7 +56,7 @@ public void BitcoinJob_Should_Accept_Valid_Share() // set clock to submission time clock.CurrentTime = DateTimeOffset.FromUnixTimeSeconds(1508869907).UtcDateTime; - var (share, blockHex, nonceSpaceUsed) = job.ProcessShare(worker, "01000000", "59ef86f2", "8d84ae6a"); + var (share, blockHex) = job.ProcessShare(worker, "01000000", "59ef86f2", "8d84ae6a"); Assert.NotNull(share); Assert.True(share.IsBlockCandidate); @@ -95,7 +95,7 @@ public void BitcoinJob_Should_Not_Accept_Invalid_Share() Assert.Throws(() => job.ProcessShare(worker, "02000000", "59ef86f2", "8d84ae6a")); // make sure we don't accept case-sensitive duplicate shares as basically 0xdeadbeaf = 0xDEADBEAF. - var (share, blockHex, nonceSpaceUsed) = job.ProcessShare(worker, "01000000", "59ef86f2", "8d84ae6a"); + var (share, blockHex) = job.ProcessShare(worker, "01000000", "59ef86f2", "8d84ae6a"); Assert.Throws(() => job.ProcessShare(worker, "01000000", "59ef86f2", "8D84AE6A")); // invalid time diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs index 39aa440ef..6faca522a 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs @@ -309,7 +309,7 @@ protected byte[] SerializeHeader(Span coinbaseHash, uint nTime, uint nonce return blockHeader.ToBytes(); } - protected virtual (Share Share, string BlockHex, double NonceSpaceUsed) ProcessShareInternal( + protected virtual (Share Share, string BlockHex) ProcessShareInternal( StratumClient worker, string extraNonce2, uint nTime, uint nonce, uint? versionBits) { var context = worker.ContextAs(); @@ -360,9 +360,6 @@ protected virtual (Share Share, string BlockHex, double NonceSpaceUsed) ProcessS Difficulty = stratumDifficulty / shareMultiplier, }; - // calculate used none-space - var nonceSpaceUsed = (double) nonce / (double) uint.MaxValue; - if (isBlockCandidate) { result.IsBlockCandidate = true; @@ -374,10 +371,10 @@ protected virtual (Share Share, string BlockHex, double NonceSpaceUsed) ProcessS var blockBytes = SerializeBlock(headerBytes, coinbase); var blockHex = blockBytes.ToHexString(); - return (result, blockHex, nonceSpaceUsed); + return (result, blockHex); } - return (result, null, nonceSpaceUsed); + return (result, null); } protected virtual byte[] SerializeCoinbase(string extraNonce1, string extraNonce2) @@ -584,13 +581,13 @@ public object GetJobParams(bool isNew) return jobParams; } - public virtual (Share Share, string BlockHex, double NonceSpaceHeight) ProcessShare(StratumClient worker, - string extraNonce2, string nTime, string nonceString, string versionBits = null) + public virtual (Share Share, string BlockHex) ProcessShare(StratumClient worker, + string extraNonce2, string nTime, string nonce, string versionBits = null) { Contract.RequiresNonNull(worker, nameof(worker)); Contract.Requires(!string.IsNullOrEmpty(extraNonce2), $"{nameof(extraNonce2)} must not be empty"); Contract.Requires(!string.IsNullOrEmpty(nTime), $"{nameof(nTime)} must not be empty"); - Contract.Requires(!string.IsNullOrEmpty(nonceString), $"{nameof(nonceString)} must not be empty"); + Contract.Requires(!string.IsNullOrEmpty(nonce), $"{nameof(nonce)} must not be empty"); var context = worker.ContextAs(); @@ -603,10 +600,10 @@ public virtual (Share Share, string BlockHex, double NonceSpaceHeight) ProcessSh throw new StratumException(StratumError.Other, "ntime out of range"); // validate nonce - if (nonceString.Length != 8) + if (nonce.Length != 8) throw new StratumException(StratumError.Other, "incorrect size of nonce"); - var nonce = uint.Parse(nonceString, NumberStyles.HexNumber); + var nonceInt = uint.Parse(nonce, NumberStyles.HexNumber); // validate version-bits (overt ASIC boost) uint versionBitsInt = 0; @@ -621,10 +618,10 @@ public virtual (Share Share, string BlockHex, double NonceSpaceHeight) ProcessSh } // dupe check - if (!RegisterSubmit(context.ExtraNonce1, extraNonce2, nTime, nonceString)) + if (!RegisterSubmit(context.ExtraNonce1, extraNonce2, nTime, nonce)) throw new StratumException(StratumError.DuplicateShare, "duplicate share"); - return ProcessShareInternal(worker, extraNonce2, nTimeInt, nonce, versionBitsInt); + return ProcessShareInternal(worker, extraNonce2, nTimeInt, nonceInt, versionBitsInt); } #endregion // API-Surface diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index 313652e90..37ba72ee5 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -182,7 +182,7 @@ public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfi base.Configure(poolConfig, clusterConfig); } - public override object[] UpdateSubscriberData(StratumClient worker) + public override object[] GetSubscriberData(StratumClient worker) { Contract.RequiresNonNull(worker, nameof(worker)); @@ -201,7 +201,7 @@ public override object[] UpdateSubscriberData(StratumClient worker) return responseData; } - public override async ValueTask<(Share Share, double NonceSpaceUsed)> SubmitShareAsync(StratumClient worker, object submission, + public override async ValueTask SubmitShareAsync(StratumClient worker, object submission, double stratumDifficultyBase, CancellationToken ct) { Contract.RequiresNonNull(worker, nameof(worker)); @@ -241,7 +241,7 @@ public override object[] UpdateSubscriberData(StratumClient worker) var workerName = split.Length > 1 ? split[1] : null; // validate & process - var (share, blockHex, nonceSpaceUsed) = job.ProcessShare(worker, extraNonce2, nTime, nonce, versionBits); + var (share, blockHex) = job.ProcessShare(worker, extraNonce2, nTime, nonce, versionBits); // enrich share with common data share.PoolId = poolConfig.Id; @@ -280,7 +280,7 @@ public override object[] UpdateSubscriberData(StratumClient worker) } } - return (share, nonceSpaceUsed); + return share; } public double ShareMultiplier => coin.ShareMultiplier; diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index 957197c38..2b36d3a9f 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -630,9 +630,9 @@ public virtual async Task ValidateAddressAsync(string address, Cancellatio return result.Response != null && result.Response.IsValid; } - public abstract object[] UpdateSubscriberData(StratumClient worker); + public abstract object[] GetSubscriberData(StratumClient worker); - public abstract ValueTask<(Share Share, double NonceSpaceUsed)> SubmitShareAsync(StratumClient worker, object submission, + public abstract ValueTask SubmitShareAsync(StratumClient worker, object submission, double stratumDifficultyBase, CancellationToken ct); #endregion // API-Surface diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs index a289b25ce..3712041d5 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs @@ -81,7 +81,7 @@ protected virtual async Task OnSubscribeAsync(StratumClient client, Timestamped< new object[] { BitcoinStratumMethods.MiningNotify, client.ConnectionId } } } - .Concat(manager.UpdateSubscriberData(client)) + .Concat(manager.GetSubscriberData(client)) .ToArray(); await client.RespondAsync(data, request.Id); @@ -159,7 +159,6 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped(); - var updateExtraNonce = false; try { @@ -188,12 +187,16 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped(); var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port]; - var (share, nonceSpaceUsed) = await manager.SubmitShareAsync(client, requestParams, poolEndpoint.Difficulty, ct); + var share = await manager.SubmitShareAsync(client, requestParams, poolEndpoint.Difficulty, ct); await client.RespondAsync(true, request.Id); // publish messageBus.SendMessage(new ClientShare(client, share)); + + // telemetry + PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, true); + logger.Info(() => $"[{client.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty * coin.ShareMultiplier, 3)}"); // update pool stats @@ -203,19 +206,9 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped= 0.95) - { - logger.Info(() => $"[{client.ConnectionId}] Assigning new extra-nonce at {(int)(nonceSpaceUsed * 100)}% NS"); - updateExtraNonce = true; - } - - // telemetry - PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, true); } - catch (StratumException ex) + catch(StratumException ex) { // telemetry PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, false); @@ -224,27 +217,10 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped $"[{client.ConnectionId}] Share rejected: {ex.Message}"); - // update extra-nonce - if (ex.Code == StratumError.DuplicateShare) - { - logger.Info(() => $"[{client.ConnectionId}] Assigning new extra-nonce on duplicate share"); - updateExtraNonce = true; - - // make sure submit is answered before updating extra-nonce - await client.RespondErrorAsync(ex.Code, ex.Message, request.Id, false); - } - // banning ConsiderBan(client, context, poolConfig.Banning); - if(!updateExtraNonce) - throw; - } - - finally - { - if (updateExtraNonce) - await UpdateExtraNonceAsync(client); + throw; } } @@ -278,17 +254,6 @@ private async Task OnSuggestDifficultyAsync(StratumClient client, Timestamped tsRequest) - { - var request = tsRequest.Value; - var context = client.ContextAs(); - - context.HasExtraNonceSubscription = true; - - // acknowledge - await client.RespondAsync(true, request.Id); - } - private async Task OnConfigureMiningAsync(StratumClient client, Timestamped tsRequest) { var request = tsRequest.Value; @@ -401,20 +366,13 @@ protected virtual async Task OnNewJobAsync(object jobParams) } } - private async Task UpdateExtraNonceAsync(StratumClient client) - { - var parameters = manager.UpdateSubscriberData(client); - await client.NotifyAsync(BitcoinStratumMethods.SetExtraNonce, parameters); - - // force work restart using new extra-nonce - await client.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); - } - public override double HashrateFromShares(double shares, double interval) { var multiplier = BitcoinConstants.Pow2x32; var result = shares * multiplier / interval; + //result *= coin.HashrateMultiplier; + return result; } @@ -505,15 +463,15 @@ protected override async Task OnRequestAsync(StratumClient client, await OnSuggestDifficultyAsync(client, tsRequest); break; - case BitcoinStratumMethods.ExtraNonceSubscribe: - await OnExtraNonceSubscribeAsync(client, tsRequest); - break; - case BitcoinStratumMethods.MiningConfigure: await OnConfigureMiningAsync(client, tsRequest); // ignored break; + case BitcoinStratumMethods.ExtraNonceSubscribe: + await client.RespondAsync(true, request.Id); + break; + case BitcoinStratumMethods.GetTransactions: // ignored break; diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinStratumMethods.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinStratumMethods.cs index 43e5a29dc..99258feef 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinStratumMethods.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinStratumMethods.cs @@ -64,11 +64,6 @@ public class BitcoinStratumMethods /// public const string ExtraNonceSubscribe = "mining.extranonce.subscribe"; - /// - /// Used to signal the miner a newly assigned extraNonce - /// - public const string SetExtraNonce = "mining.set_extranonce"; - /// /// Appears to be a command sent by AntMiner devices for use with ASICBOOST. /// https://www.reddit.com/r/Bitcoin/comments/63yo27/some_circumstantial_evidence_supporting_the_claim/dfy5o65/ diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinWorkerContext.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinWorkerContext.cs index a6706c76b..d316b8090 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinWorkerContext.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinWorkerContext.cs @@ -36,11 +36,6 @@ public class BitcoinWorkerContext : WorkerContextBase public string ExtraNonce1 { get; set; } - /// - /// Client has requested on-the-fly changes for ExtraNonce1 - /// - public bool HasExtraNonceSubscription { get; internal set; } - /// /// Mask for version-rolling (Overt ASIC-Boost) /// diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index bf4cb5ff3..eea887391 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -214,7 +214,7 @@ public override async Task ValidateAddressAsync(string address, Cancellati return result.Response != null && result.Response.IsValid; } - public override object[] UpdateSubscriberData(StratumClient worker) + public override object[] GetSubscriberData(StratumClient worker) { Contract.RequiresNonNull(worker, nameof(worker)); @@ -232,7 +232,7 @@ public override object[] UpdateSubscriberData(StratumClient worker) return responseData; } - public override async ValueTask<(Share Share, double NonceSpaceUsed)> SubmitShareAsync(StratumClient worker, object submission, + public override async ValueTask SubmitShareAsync(StratumClient worker, object submission, double stratumDifficultyBase, CancellationToken ct) { Contract.RequiresNonNull(worker, nameof(worker)); @@ -315,7 +315,7 @@ public override object[] UpdateSubscriberData(StratumClient worker) share.Difficulty = share.Difficulty; share.Created = clock.Now; - return (share, 0); + return share; } diff --git a/src/Miningcore/Blockchain/Equihash/EquihashPool.cs b/src/Miningcore/Blockchain/Equihash/EquihashPool.cs index c9af38038..5e687e8ee 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashPool.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashPool.cs @@ -141,7 +141,7 @@ protected async Task OnSubscribeAsync(StratumClient client, Timestamped(); var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port]; - var (share, _) = await manager.SubmitShareAsync(client, requestParams, poolEndpoint.Difficulty, ct); + var share = await manager.SubmitShareAsync(client, requestParams, poolEndpoint.Difficulty, ct); await client.RespondAsync(true, request.Id); diff --git a/src/Miningcore/Blockchain/ExtraNonceProviderBase.cs b/src/Miningcore/Blockchain/ExtraNonceProviderBase.cs index 0741e51ea..9cfcc36bf 100644 --- a/src/Miningcore/Blockchain/ExtraNonceProviderBase.cs +++ b/src/Miningcore/Blockchain/ExtraNonceProviderBase.cs @@ -58,7 +58,7 @@ public string Next() { counter++; if (counter > nonceMax) - counter = 1; + counter = 0; // encode to hex var result = counter.ToString(stringFormat); From 73b6aa584ad9be2dc51a49932226de5460e86788 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 14 Nov 2018 11:43:08 +0100 Subject: [PATCH 060/178] Dash v13 changes --- .../Blockchain/Bitcoin/BitcoinJob.cs | 55 ++++++++++++++----- .../Bitcoin/DaemonResponses/Masternode.cs | 6 +- src/Miningcore/Miningcore.csproj | 2 +- 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs index 6faca522a..d6bce69fb 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs @@ -34,6 +34,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using Miningcore.Util; using NBitcoin; using NBitcoin.DataEncoders; +using Newtonsoft.Json.Linq; using Contract = Miningcore.Contracts.Contract; using Transaction = NBitcoin.Transaction; @@ -176,6 +177,12 @@ protected virtual void AppendCoinbaseFinal(BitcoinStream bs) var data = Encoding.ASCII.GetBytes(txComment); bs.ReadWriteAsVarString(ref data); } + + if (coin.HasMasterNodes && !string.IsNullOrEmpty(masterNodeParameters.CoinbasePayload)) + { + var data = masterNodeParameters.CoinbasePayload.HexToByteArray(); + bs.ReadWriteAsVarString(ref data); + } } protected virtual byte[] SerializeOutputTransaction(Transaction tx) @@ -454,25 +461,22 @@ protected virtual Transaction CreateMasternodeOutputTransaction() protected virtual Money CreateMasternodeOutputs(Transaction tx, Money reward) { - if (masterNodeParameters.Masternode != null && masterNodeParameters.SuperBlocks != null) + if (masterNodeParameters.Masternode != null) { - if (!string.IsNullOrEmpty(masterNodeParameters.Masternode.Payee)) - { - var payeeAddress = BitcoinUtils.AddressToDestination(masterNodeParameters.Masternode.Payee, network); - var payeeReward = masterNodeParameters.Masternode.Amount; + Masternode[] masternodes; - reward -= payeeReward; - rewardToPool -= payeeReward; - - tx.Outputs.Add(payeeReward, payeeAddress); - } + // Dash v13 Multi-Master-Nodes + if (masterNodeParameters.Masternode.Type == JTokenType.Array) + masternodes = masterNodeParameters.Masternode.ToObject(); + else + masternodes = new[] { masterNodeParameters.Masternode.ToObject() }; - else if (masterNodeParameters.SuperBlocks.Length > 0) + foreach(var masterNode in masternodes) { - foreach (var superBlock in masterNodeParameters.SuperBlocks) + if (!string.IsNullOrEmpty(masterNode.Payee)) { - var payeeAddress = BitcoinUtils.AddressToDestination(superBlock.Payee, network); - var payeeReward = superBlock.Amount; + var payeeAddress = BitcoinUtils.AddressToDestination(masterNode.Payee, network); + var payeeReward = masterNode.Amount; reward -= payeeReward; rewardToPool -= payeeReward; @@ -482,6 +486,20 @@ protected virtual Money CreateMasternodeOutputs(Transaction tx, Money reward) } } + if (masterNodeParameters.SuperBlocks != null && masterNodeParameters.SuperBlocks.Length > 0) + { + foreach (var superBlock in masterNodeParameters.SuperBlocks) + { + var payeeAddress = BitcoinUtils.AddressToDestination(superBlock.Payee, network); + var payeeReward = superBlock.Amount; + + reward -= payeeReward; + rewardToPool -= payeeReward; + + tx.Outputs.Add(payeeReward, payeeAddress); + } + } + if (!string.IsNullOrEmpty(masterNodeParameters.Payee)) { var payeeAddress = BitcoinUtils.AddressToDestination(masterNodeParameters.Payee, network); @@ -539,8 +557,17 @@ public void Init(BlockTemplate blockTemplate, string jobId, extraPoolConfig.CoinbaseTxComment : coin.CoinbaseTxComment; if (coin.HasMasterNodes) + { masterNodeParameters = BlockTemplate.Extra.SafeExtensionDataAs(); + if(!string.IsNullOrEmpty(masterNodeParameters.CoinbasePayload)) + { + txVersion = 3; + var txType = 5; + txVersion = txVersion + ((uint) (txType << 16)); + } + } + this.coinbaseHasher = coinbaseHasher; this.headerHasher = headerHasher; this.blockHasher = blockHasher; diff --git a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Masternode.cs b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Masternode.cs index 4f06a7a35..ad664df3a 100644 --- a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Masternode.cs +++ b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Masternode.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Text; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Miningcore.Blockchain.Bitcoin.DaemonResponses { @@ -25,7 +26,7 @@ public class MasterNodeBlockTemplateExtra [JsonProperty("payee_amount")] public long? PayeeAmount { get; set; } - public Masternode Masternode { get; set; } + public JToken Masternode { get; set; } [JsonProperty("masternode_payments_started")] public bool MasternodePaymentsStarted { get; set; } @@ -41,5 +42,8 @@ public class MasterNodeBlockTemplateExtra [JsonProperty("superblocks_enabled")] public bool SuperblocksEnabled { get; set; } + + [JsonProperty("coinbase_payload")] + public string CoinbasePayload { get; set; } } } diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index db4bae3c8..7e53d6cb5 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -58,7 +58,7 @@ - + From 31fad67d4c3f3e59e9ebef417721cfaa816b747e Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 14 Nov 2018 15:04:09 +0100 Subject: [PATCH 061/178] BTH test --- src/Miningcore/coins.json | 45 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index 187b4b3fe..f97c7cdb2 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -1131,6 +1131,51 @@ "explorerTxLink": "https://explorer.bitcoingold.org/insight/tx/{0}", "explorerAccountLink": "https://explorer.bitcoingold.org/insight/address/{0}" }, + "bithereum": { + "name": "Bithereum", + "symbol": "BTH", + "family": "equihash", + "networks": { + "main": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 100, + "solutionPreambleSize": 1, + "solver": { + "hash": "equihash", + "args": [ 144, 5, "BethdPoW" ] + }, + "coinbaseTxNetwork": "main", + "payFoundersReward": false + }, + "test": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 100, + "solutionPreambleSize": 1, + "solver": { + "hash": "equihash", + "args": [ 144, 5, "BethdPoW" ] + }, + "coinbaseTxNetwork": "testnet", + "payFoundersReward": false + }, + "regtest": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 100, + "solutionPreambleSize": 1, + "solver": { + "hash": "equihash", + "args": [ 144, 5, "BethdPoW" ] + }, + "coinbaseTxNetwork": "regtest", + "payFoundersReward": false + } + }, + "usesZCashAddressFormat": false, + "useBitcoinPayoutHandler": true, + "explorerBlockLink": "https://explorer.bithereum.network/block/$hash$", + "explorerTxLink": "https://explorer.bithereum.network/tx/{0}", + "explorerAccountLink": "https://explorer.bithereum.network/address/{0}" + }, "minexcoin": { "name": "Minexcoin", "symbol": "MNX", From 6ed0ce22c20e50466cabf3cb408e1552a2261290 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 14 Nov 2018 21:00:19 +0100 Subject: [PATCH 062/178] Enhance pool/blocks API with block state parameter support --- src/Miningcore/Api/Controllers/PoolApiController.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Miningcore/Api/Controllers/PoolApiController.cs b/src/Miningcore/Api/Controllers/PoolApiController.cs index 2afdb7ed1..78cf75dc6 100644 --- a/src/Miningcore/Api/Controllers/PoolApiController.cs +++ b/src/Miningcore/Api/Controllers/PoolApiController.cs @@ -166,12 +166,15 @@ public async Task PagePoolMinersAsync( [HttpGet("{poolId}/blocks")] public async Task PagePoolBlocksPagedAsync( - string poolId, [FromQuery] int page, [FromQuery] int pageSize) + string poolId, [FromQuery] int page, [FromQuery] int pageSize, [FromQuery] BlockStatus[] state) { var pool = GetPool(poolId); - var blocks = (await cf.Run(con => blocksRepo.PageBlocksAsync(con, pool.Id, - new[] { BlockStatus.Confirmed, BlockStatus.Pending, BlockStatus.Orphaned }, page, pageSize))) + var blockStates = state != null && state.Length > 0 ? + state : + new[] { BlockStatus.Confirmed, BlockStatus.Pending, BlockStatus.Orphaned }; + + var blocks = (await cf.Run(con => blocksRepo.PageBlocksAsync(con, pool.Id, blockStates, page, pageSize))) .Select(mapper.Map) .ToArray(); From f624db49aa1058237c5fd4fed73e98dad5da3a56 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 14 Nov 2018 21:26:31 +0100 Subject: [PATCH 063/178] Cluster API controller --- .../Api/Controllers/ClusterApiController.cs | 108 ++++++++++++++++++ .../Api/Responses/GetBlocksResponse.cs | 1 + .../Postgres/Repositories/BlockRepository.cs | 15 +++ .../Repositories/IBlockRepository.cs | 1 + 4 files changed, 125 insertions(+) create mode 100644 src/Miningcore/Api/Controllers/ClusterApiController.cs diff --git a/src/Miningcore/Api/Controllers/ClusterApiController.cs b/src/Miningcore/Api/Controllers/ClusterApiController.cs new file mode 100644 index 000000000..ecd12b2e4 --- /dev/null +++ b/src/Miningcore/Api/Controllers/ClusterApiController.cs @@ -0,0 +1,108 @@ +using Autofac; +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using Miningcore.Api.Extensions; +using Miningcore.Api.Responses; +using Miningcore.Blockchain; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.Mining; +using Miningcore.Persistence; +using Miningcore.Persistence.Model; +using Miningcore.Persistence.Model.Projections; +using Miningcore.Persistence.Repositories; +using Miningcore.Time; +using System; +using System.Collections.Concurrent; +using System.Data; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Threading.Tasks; + +namespace Miningcore.Api.Controllers +{ + [Route("api")] + [ApiController] + public class ClusterApiController : ControllerBase + { + public ClusterApiController(IComponentContext ctx) + { + clusterConfig = ctx.Resolve(); + cf = ctx.Resolve(); + statsRepo = ctx.Resolve(); + blocksRepo = ctx.Resolve(); + paymentsRepo = ctx.Resolve(); + mapper = ctx.Resolve(); + clock = ctx.Resolve(); + pools = ctx.Resolve>(); + } + + private readonly ClusterConfig clusterConfig; + private readonly IConnectionFactory cf; + private readonly IStatsRepository statsRepo; + private readonly IBlockRepository blocksRepo; + private readonly IPaymentRepository paymentsRepo; + private readonly IMapper mapper; + private readonly IMasterClock clock; + private readonly ConcurrentDictionary pools; + + #region Actions + + [HttpGet("blocks")] + public async Task PageBlocksPagedAsync( + [FromQuery] int page, [FromQuery] int pageSize, [FromQuery] BlockStatus[] state) + { + var blockStates = state != null && state.Length > 0 ? + state : + new[] { BlockStatus.Confirmed, BlockStatus.Pending, BlockStatus.Orphaned }; + + var blocks = (await cf.Run(con => blocksRepo.PageBlocksAsync(con, blockStates, page, pageSize))) + .Select(mapper.Map) + .ToArray(); + + // enrich blocks + var blocksByPool = blocks.GroupBy(x => x.PoolId); + + foreach (var poolBlocks in blocksByPool) + { + var pool = GetPoolNoThrow(poolBlocks.Key); + + if (pool == null) + continue; + + var blockInfobaseDict = pool.Template.ExplorerBlockLinks; + + // compute infoLink + if (blockInfobaseDict != null) + { + foreach (var block in poolBlocks) + { + blockInfobaseDict.TryGetValue(!string.IsNullOrEmpty(block.Type) ? block.Type : "block", out var blockInfobaseUrl); + + if (!string.IsNullOrEmpty(blockInfobaseUrl)) + { + if (blockInfobaseUrl.Contains(CoinMetaData.BlockHeightPH)) + block.InfoLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHeightPH, block.BlockHeight.ToString(CultureInfo.InvariantCulture)); + else if (blockInfobaseUrl.Contains(CoinMetaData.BlockHashPH) && !string.IsNullOrEmpty(block.Hash)) + block.InfoLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHashPH, block.Hash); + } + } + } + } + + return blocks; + } + + #endregion // Actions + + private PoolConfig GetPoolNoThrow(string poolId) + { + if (string.IsNullOrEmpty(poolId)) + return null; + + var pool = clusterConfig.Pools.FirstOrDefault(x => x.Id == poolId && x.Enabled); + return pool; + } + } +} diff --git a/src/Miningcore/Api/Responses/GetBlocksResponse.cs b/src/Miningcore/Api/Responses/GetBlocksResponse.cs index 6e2772e4f..aee3cd047 100644 --- a/src/Miningcore/Api/Responses/GetBlocksResponse.cs +++ b/src/Miningcore/Api/Responses/GetBlocksResponse.cs @@ -24,6 +24,7 @@ namespace Miningcore.Api.Responses { public class Block { + public string PoolId { get; set; } public ulong BlockHeight { get; set; } public double NetworkDifficulty { get; set; } public string Status { get; set; } diff --git a/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs index 6ef0a6be4..11d646d57 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs @@ -89,6 +89,21 @@ public async Task PageBlocksAsync(IDbConnection con, string poolId, Blo })) .Select(mapper.Map) .ToArray(); + } + + public async Task PageBlocksAsync(IDbConnection con, BlockStatus[] status, int page, int pageSize) + { + const string query = "SELECT * FROM blocks WHERE status = ANY(@status) " + + "ORDER BY created DESC OFFSET @offset FETCH NEXT (@pageSize) ROWS ONLY"; + + return (await con.QueryAsync(query, new + { + status = status.Select(x => x.ToString().ToLower()).ToArray(), + offset = page * pageSize, + pageSize + })) + .Select(mapper.Map) + .ToArray(); } public async Task GetPendingBlocksForPoolAsync(IDbConnection con, string poolId) diff --git a/src/Miningcore/Persistence/Repositories/IBlockRepository.cs b/src/Miningcore/Persistence/Repositories/IBlockRepository.cs index 627ae8da3..3dda0018a 100644 --- a/src/Miningcore/Persistence/Repositories/IBlockRepository.cs +++ b/src/Miningcore/Persistence/Repositories/IBlockRepository.cs @@ -32,6 +32,7 @@ public interface IBlockRepository Task UpdateBlockAsync(IDbConnection con, IDbTransaction tx, Block block); Task PageBlocksAsync(IDbConnection con, string poolId, BlockStatus[] status, int page, int pageSize); + Task PageBlocksAsync(IDbConnection con, BlockStatus[] status, int page, int pageSize); Task GetPendingBlocksForPoolAsync(IDbConnection con, string poolId); Task GetBlockBeforeAsync(IDbConnection con, string poolId, BlockStatus[] status, DateTime before); } From fc4ba36e2a741b46b2e31cab25cc6bd488b06bc7 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 14 Nov 2018 21:38:25 +0100 Subject: [PATCH 064/178] Don't return blocks for disabled pools. --- src/Miningcore/Api/Controllers/ClusterApiController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Api/Controllers/ClusterApiController.cs b/src/Miningcore/Api/Controllers/ClusterApiController.cs index ecd12b2e4..2228a65c8 100644 --- a/src/Miningcore/Api/Controllers/ClusterApiController.cs +++ b/src/Miningcore/Api/Controllers/ClusterApiController.cs @@ -68,7 +68,7 @@ public ClusterApiController(IComponentContext ctx) { var pool = GetPoolNoThrow(poolBlocks.Key); - if (pool == null) + if (pool == null || !pool.Enabled) continue; var blockInfobaseDict = pool.Template.ExplorerBlockLinks; From 0fd0c204b8f2d98d332eb6942cb017b7f4c62077 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 14 Nov 2018 21:43:17 +0100 Subject: [PATCH 065/178] WIP --- src/Miningcore/Api/Controllers/ClusterApiController.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Miningcore/Api/Controllers/ClusterApiController.cs b/src/Miningcore/Api/Controllers/ClusterApiController.cs index 2228a65c8..80903dd1c 100644 --- a/src/Miningcore/Api/Controllers/ClusterApiController.cs +++ b/src/Miningcore/Api/Controllers/ClusterApiController.cs @@ -14,6 +14,7 @@ using Miningcore.Time; using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Data; using System.Globalization; using System.Linq; @@ -53,12 +54,15 @@ public ClusterApiController(IComponentContext ctx) public async Task PageBlocksPagedAsync( [FromQuery] int page, [FromQuery] int pageSize, [FromQuery] BlockStatus[] state) { + var enabledPools = new HashSet(clusterConfig.Pools.Where(x => x.Enabled).Select(x=> x.Id)); + var blockStates = state != null && state.Length > 0 ? state : new[] { BlockStatus.Confirmed, BlockStatus.Pending, BlockStatus.Orphaned }; var blocks = (await cf.Run(con => blocksRepo.PageBlocksAsync(con, blockStates, page, pageSize))) .Select(mapper.Map) + .Where(x=> enabledPools.Contains(x.PoolId)) .ToArray(); // enrich blocks @@ -68,7 +72,7 @@ public ClusterApiController(IComponentContext ctx) { var pool = GetPoolNoThrow(poolBlocks.Key); - if (pool == null || !pool.Enabled) + if (pool == null) continue; var blockInfobaseDict = pool.Template.ExplorerBlockLinks; From 23736c22283b0df2160c0caa03ed1ddd71de2eb1 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 14 Nov 2018 21:44:38 +0100 Subject: [PATCH 066/178] WIP --- src/Miningcore/Api/Controllers/ClusterApiController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Miningcore/Api/Controllers/ClusterApiController.cs b/src/Miningcore/Api/Controllers/ClusterApiController.cs index 80903dd1c..a8a8ccd83 100644 --- a/src/Miningcore/Api/Controllers/ClusterApiController.cs +++ b/src/Miningcore/Api/Controllers/ClusterApiController.cs @@ -37,6 +37,7 @@ public ClusterApiController(IComponentContext ctx) mapper = ctx.Resolve(); clock = ctx.Resolve(); pools = ctx.Resolve>(); + enabledPools = new HashSet(clusterConfig.Pools.Where(x => x.Enabled).Select(x => x.Id)); } private readonly ClusterConfig clusterConfig; @@ -47,6 +48,7 @@ public ClusterApiController(IComponentContext ctx) private readonly IMapper mapper; private readonly IMasterClock clock; private readonly ConcurrentDictionary pools; + private readonly HashSet enabledPools; #region Actions @@ -54,8 +56,6 @@ public ClusterApiController(IComponentContext ctx) public async Task PageBlocksPagedAsync( [FromQuery] int page, [FromQuery] int pageSize, [FromQuery] BlockStatus[] state) { - var enabledPools = new HashSet(clusterConfig.Pools.Where(x => x.Enabled).Select(x=> x.Id)); - var blockStates = state != null && state.Length > 0 ? state : new[] { BlockStatus.Confirmed, BlockStatus.Pending, BlockStatus.Orphaned }; From 585c16eac61da809753991163e7bdc361c25d067 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Thu, 15 Nov 2018 20:26:43 +0100 Subject: [PATCH 067/178] Block Id in API responses --- src/Miningcore/Api/Responses/GetBlocksResponse.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Miningcore/Api/Responses/GetBlocksResponse.cs b/src/Miningcore/Api/Responses/GetBlocksResponse.cs index aee3cd047..48bf2e4d1 100644 --- a/src/Miningcore/Api/Responses/GetBlocksResponse.cs +++ b/src/Miningcore/Api/Responses/GetBlocksResponse.cs @@ -24,6 +24,7 @@ namespace Miningcore.Api.Responses { public class Block { + public string Id { get; set; } public string PoolId { get; set; } public ulong BlockHeight { get; set; } public double NetworkDifficulty { get; set; } From 5614c42ebf537def4ad397ace2aeda661c5913e9 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 16 Nov 2018 09:35:10 +0100 Subject: [PATCH 068/178] Revert "Block Id in API responses" This reverts commit 585c16eac61da809753991163e7bdc361c25d067. --- src/Miningcore/Api/Responses/GetBlocksResponse.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Miningcore/Api/Responses/GetBlocksResponse.cs b/src/Miningcore/Api/Responses/GetBlocksResponse.cs index 48bf2e4d1..aee3cd047 100644 --- a/src/Miningcore/Api/Responses/GetBlocksResponse.cs +++ b/src/Miningcore/Api/Responses/GetBlocksResponse.cs @@ -24,7 +24,6 @@ namespace Miningcore.Api.Responses { public class Block { - public string Id { get; set; } public string PoolId { get; set; } public ulong BlockHeight { get; set; } public double NetworkDifficulty { get; set; } From 9629f43bc167140a9d611911830c2e86d128d5e4 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sun, 18 Nov 2018 13:46:45 +0100 Subject: [PATCH 069/178] ETH logging --- src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs index 33abbf7ed..19dc5cc9e 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs @@ -35,7 +35,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using Miningcore.Blockchain.Ethereum.Configuration; using Miningcore.Blockchain.Ethereum.DaemonResponses; using Miningcore.Configuration; -using Miningcore.Crypto.Hashing.Algorithms; using Miningcore.Crypto.Hashing.Ethash; using Miningcore.DaemonInterface; using Miningcore.Extensions; @@ -706,7 +705,7 @@ protected virtual async Task SetupJobUpdatesAsync() .Do(isNew => { if (isNew) - logger.Info(() => $"New block {currentJob.BlockTemplate.Height} detected"); + logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected via WebSocket"); }) .Where(isNew => isNew) .Select(_ => GetJobParamsForStratum(true)) @@ -749,7 +748,7 @@ protected virtual async Task SetupJobUpdatesAsync() .Do(isNew => { if (isNew) - logger.Info(() => $"Detected new block {currentJob.BlockTemplate.Height} via WebSocket"); + logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected via WebSocket"); }) .Where(isNew => isNew) .Select(_ => GetJobParamsForStratum(true)) @@ -768,7 +767,7 @@ protected virtual async Task SetupJobUpdatesAsync() .Do(isNew => { if (isNew) - logger.Info(() => $"Detected new block {currentJob.BlockTemplate.Height} via RPC Polling"); + logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected via RPC-Polling"); }) .Where(isNew => isNew) .Select(_ => GetJobParamsForStratum(true)) @@ -788,7 +787,7 @@ protected virtual async Task SetupJobUpdatesAsync() .Do(isNew => { if (isNew) - logger.Info(() => $"Detected new block {currentJob.BlockTemplate.Height} via BT-Stream"); + logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected via BT-Stream"); }) .Where(isNew => isNew) .Select(_ => GetJobParamsForStratum(true)) From 8ffced9305585ef08be5130abf72f3e4c93dd4ce Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 19 Nov 2018 15:29:04 +0100 Subject: [PATCH 070/178] Setup --- .../Bitcoin/BitcoinJobManagerBase.cs | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index 2b36d3a9f..ac508c95d 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -483,7 +483,7 @@ protected override async Task PostStartInitAsync(CancellationToken ct) } // extract results - var validateAddressResponse = results[0].Response.ToObject(); + var validateAddressResponse = results[0].Error == null ? results[0].Response.ToObject() : null; var submitBlockResponse = results[1]; var blockchainInfoResponse = !hasLegacyDaemon ? results[2].Response.ToObject() : null; var daemonInfoResponse = hasLegacyDaemon ? results[2].Response.ToObject() : null; @@ -498,29 +498,27 @@ protected override async Task PostStartInitAsync(CancellationToken ct) PostChainIdentifyConfigure(); // ensure pool owns wallet - if (!validateAddressResponse.IsValid) + if (validateAddressResponse == null || !validateAddressResponse.IsValid) logger.ThrowLogPoolStartupException($"Daemon reports pool-address '{poolConfig.Address}' as invalid"); - //if (clusterConfig.PaymentProcessing?.Enabled == true && !validateAddressResponse.IsMine) - // logger.ThrowLogPoolStartupException($"Daemon does not own pool-address '{poolConfig.Address}'", LogCat); - isPoS = difficultyResponse.Values().Any(x => x.Path == "proof-of-stake"); // Create pool address script from response if (!isPoS) - { - // bitcoincashd returns a different address than what was passed in - if (!validateAddressResponse.Address.StartsWith("bitcoincash:")) - poolAddressDestination = AddressToDestination(validateAddressResponse.Address, extraPoolConfig?.AddressType); - else - poolAddressDestination = AddressToDestination(poolConfig.Address, extraPoolConfig?.AddressType); - } - + poolAddressDestination = AddressToDestination(poolConfig.Address, extraPoolConfig?.AddressType); else poolAddressDestination = new PubKey(validateAddressResponse.PubKey); - if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + // Payment-processing setup + if (clusterConfig.PaymentProcessing?.Enabled == true && + poolConfig.PaymentProcessing?.Enabled == true) + { + // ensure pool owns wallet + if (!validateAddressResponse.IsMine) + logger.ThrowLogPoolStartupException($"Daemon does not own pool-address '{poolConfig.Address}'"); + ConfigureRewards(); + } // update stats BlockchainStats.NetworkType = network.Name; From 8ba198aa0f295c2507280044cbd4b4d6d33b08c5 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 19 Nov 2018 15:33:51 +0100 Subject: [PATCH 071/178] WIP --- src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index ac508c95d..f3d9418a5 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -510,8 +510,7 @@ protected override async Task PostStartInitAsync(CancellationToken ct) poolAddressDestination = new PubKey(validateAddressResponse.PubKey); // Payment-processing setup - if (clusterConfig.PaymentProcessing?.Enabled == true && - poolConfig.PaymentProcessing?.Enabled == true) + if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) { // ensure pool owns wallet if (!validateAddressResponse.IsMine) From f70c89660803a11e11b7996b64876545752fbd53 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 19 Nov 2018 15:44:26 +0100 Subject: [PATCH 072/178] Pool pubkey support for POS contains (if daemon does not have wallet matching pool address) --- src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs | 2 +- src/Miningcore/Configuration/ClusterConfig.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index f3d9418a5..4a71045f9 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -507,7 +507,7 @@ protected override async Task PostStartInitAsync(CancellationToken ct) if (!isPoS) poolAddressDestination = AddressToDestination(poolConfig.Address, extraPoolConfig?.AddressType); else - poolAddressDestination = new PubKey(validateAddressResponse.PubKey); + poolAddressDestination = new PubKey(poolConfig.PubKey ?? validateAddressResponse.PubKey); // Payment-processing setup if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index f1dc83aed..0b2a7168e 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -633,6 +633,7 @@ public partial class PoolConfig public PoolShareBasedBanningConfig Banning { get; set; } public RewardRecipient[] RewardRecipients { get; set; } public string Address { get; set; } + public string PubKey { get; set; } // POS coins only public int ClientConnectionTimeout { get; set; } public int JobRebroadcastTimeout { get; set; } public int BlockRefreshInterval { get; set; } From 8875f4738b6b939af7ca6dc1a2fd7c6dcf2b5b66 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 19 Nov 2018 23:30:28 +0100 Subject: [PATCH 073/178] x22i hash --- libs/runtimes/win-x64/libmultihash.dll | Bin 1104896 -> 1171456 bytes src/Miningcore.Tests/Crypto/HashingTests.cs | 11 + .../Crypto/Hashing/Algorithms/X22i.cs | 42 + src/Miningcore/Native/LibMultihash.cs | 3 + src/Native/libmultihash/Makefile | 3 +- src/Native/libmultihash/SWIFFTX/SWIFFTX.c | 1155 +++++++++++++++++ src/Native/libmultihash/SWIFFTX/SWIFFTX.h | 80 ++ .../libmultihash/SWIFFTX/Swifftx_sha3.cpp | 369 ++++++ .../libmultihash/SWIFFTX/Swifftx_sha3.h | 79 ++ .../libmultihash/SWIFFTX/hash_interface.h | 21 + src/Native/libmultihash/SWIFFTX/inttypes.h | 41 + .../libmultihash/SWIFFTX/sha3_interface.h | 13 + src/Native/libmultihash/SWIFFTX/stdbool.h | 46 + src/Native/libmultihash/SWIFFTX/stdint.h | 54 + src/Native/libmultihash/equi/uint256.cpp | 7 + src/Native/libmultihash/equi/uint256.h | 13 + src/Native/libmultihash/exports.cpp | 6 + src/Native/libmultihash/gost_streebog.c | 1023 +++++++++++++++ src/Native/libmultihash/gost_streebog.h | 185 +++ src/Native/libmultihash/libmultihash.vcxproj | 8 + .../libmultihash/libmultihash.vcxproj.filters | 24 + src/Native/libmultihash/sha3/sph_tiger.c | 697 ++++++++++ src/Native/libmultihash/sha3/sph_tiger.h | 191 +++ src/Native/libmultihash/x22i.cpp | 165 +++ src/Native/libmultihash/x22i.h | 8 + 25 files changed, 4243 insertions(+), 1 deletion(-) create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/X22i.cs create mode 100644 src/Native/libmultihash/SWIFFTX/SWIFFTX.c create mode 100644 src/Native/libmultihash/SWIFFTX/SWIFFTX.h create mode 100644 src/Native/libmultihash/SWIFFTX/Swifftx_sha3.cpp create mode 100644 src/Native/libmultihash/SWIFFTX/Swifftx_sha3.h create mode 100644 src/Native/libmultihash/SWIFFTX/hash_interface.h create mode 100644 src/Native/libmultihash/SWIFFTX/inttypes.h create mode 100644 src/Native/libmultihash/SWIFFTX/sha3_interface.h create mode 100644 src/Native/libmultihash/SWIFFTX/stdbool.h create mode 100644 src/Native/libmultihash/SWIFFTX/stdint.h create mode 100644 src/Native/libmultihash/gost_streebog.c create mode 100644 src/Native/libmultihash/gost_streebog.h create mode 100644 src/Native/libmultihash/sha3/sph_tiger.c create mode 100644 src/Native/libmultihash/sha3/sph_tiger.h create mode 100644 src/Native/libmultihash/x22i.cpp create mode 100644 src/Native/libmultihash/x22i.h diff --git a/libs/runtimes/win-x64/libmultihash.dll b/libs/runtimes/win-x64/libmultihash.dll index c13cc707ad629a917eec2a62dbd0b83370c2046d..035567d25765002ab3c8608bec31c54f0230f501 100644 GIT binary patch delta 229640 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

a%=K7s^?z$wV!+gxpVc`7ts>6& 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

!3(ated!q* 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�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

public string CoinbaseTxComment { get; set; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool HasPayee { get; set; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool HasMasterNodes { get; set; } From 81a346bac4d42d6da76abca13fcaec1a8cbf0e84 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 23 Nov 2018 10:46:24 +0100 Subject: [PATCH 078/178] Ban on SSL handshake error --- src/Miningcore/Stratum/StratumClient.cs | 3 ++- src/Miningcore/Stratum/StratumServer.cs | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Miningcore/Stratum/StratumClient.cs b/src/Miningcore/Stratum/StratumClient.cs index fd6c40b23..d559540de 100644 --- a/src/Miningcore/Stratum/StratumClient.cs +++ b/src/Miningcore/Stratum/StratumClient.cs @@ -118,7 +118,8 @@ public void Run(Socket socket, socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); // create stream - networkStream = new NetworkStream(socket, true); + networkStream = new NetworkStream(socket, true); + logger.Info(() => $"[{ConnectionId}] Accepting connection from {RemoteEndpoint.Address}:{RemoteEndpoint.Port} ..."); using (var disposables = new CompositeDisposable(networkStream, cts)) { diff --git a/src/Miningcore/Stratum/StratumServer.cs b/src/Miningcore/Stratum/StratumServer.cs index 3c724a796..a1e71a246 100644 --- a/src/Miningcore/Stratum/StratumServer.cs +++ b/src/Miningcore/Stratum/StratumServer.cs @@ -276,6 +276,17 @@ protected virtual void OnClientError(StratumClient client, Exception ex) } break; + case AuthenticationException authEx: + // junk received (SSL handshake) + logger.Error(() => $"[{client.ConnectionId}] Connection json error state: {authEx.Message}"); + + if (clusterConfig.Banning?.BanOnJunkReceive.HasValue == false || clusterConfig.Banning?.BanOnJunkReceive == true) + { + logger.Info(() => $"[{client.ConnectionId}] Banning client for sending junk"); + banManager?.Ban(client.RemoteEndpoint.Address, TimeSpan.FromMinutes(30)); + } + break; + case ObjectDisposedException odEx: // socket disposed break; From cc22cae265db737f56a2d1ec0541ab65c7d5429d Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 23 Nov 2018 10:56:12 +0100 Subject: [PATCH 079/178] WIP --- src/Miningcore/Stratum/StratumServer.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Miningcore/Stratum/StratumServer.cs b/src/Miningcore/Stratum/StratumServer.cs index a1e71a246..dd163ee47 100644 --- a/src/Miningcore/Stratum/StratumServer.cs +++ b/src/Miningcore/Stratum/StratumServer.cs @@ -275,18 +275,32 @@ protected virtual void OnClientError(StratumClient client, Exception ex) banManager?.Ban(client.RemoteEndpoint.Address, TimeSpan.FromMinutes(30)); } break; - + case AuthenticationException authEx: // junk received (SSL handshake) logger.Error(() => $"[{client.ConnectionId}] Connection json error state: {authEx.Message}"); if (clusterConfig.Banning?.BanOnJunkReceive.HasValue == false || clusterConfig.Banning?.BanOnJunkReceive == true) { - logger.Info(() => $"[{client.ConnectionId}] Banning client for sending junk"); + logger.Info(() => $"[{client.ConnectionId}] Banning client for failing SSL handshake"); banManager?.Ban(client.RemoteEndpoint.Address, TimeSpan.FromMinutes(30)); } break; + case IOException ioEx: + // junk received (SSL handshake) + logger.Error(() => $"[{client.ConnectionId}] Connection json error state: {ioEx.Message}"); + + if (ioEx.Source == "System.Net.Security") + { + if (clusterConfig.Banning?.BanOnJunkReceive.HasValue == false || clusterConfig.Banning?.BanOnJunkReceive == true) + { + logger.Info(() => $"[{client.ConnectionId}] Banning client for failing SSL handshake"); + banManager?.Ban(client.RemoteEndpoint.Address, TimeSpan.FromMinutes(30)); + } + } + break; + case ObjectDisposedException odEx: // socket disposed break; From 3b6e230f40479da829f58c54075a513a01cfbe39 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 23 Nov 2018 10:57:17 +0100 Subject: [PATCH 080/178] WIP --- src/Miningcore/Stratum/StratumServer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Miningcore/Stratum/StratumServer.cs b/src/Miningcore/Stratum/StratumServer.cs index dd163ee47..dc12035b6 100644 --- a/src/Miningcore/Stratum/StratumServer.cs +++ b/src/Miningcore/Stratum/StratumServer.cs @@ -272,7 +272,7 @@ protected virtual void OnClientError(StratumClient client, Exception ex) if (clusterConfig.Banning?.BanOnJunkReceive.HasValue == false || clusterConfig.Banning?.BanOnJunkReceive == true) { logger.Info(() => $"[{client.ConnectionId}] Banning client for sending junk"); - banManager?.Ban(client.RemoteEndpoint.Address, TimeSpan.FromMinutes(30)); + banManager?.Ban(client.RemoteEndpoint.Address, TimeSpan.FromMinutes(3)); } break; @@ -283,7 +283,7 @@ protected virtual void OnClientError(StratumClient client, Exception ex) if (clusterConfig.Banning?.BanOnJunkReceive.HasValue == false || clusterConfig.Banning?.BanOnJunkReceive == true) { logger.Info(() => $"[{client.ConnectionId}] Banning client for failing SSL handshake"); - banManager?.Ban(client.RemoteEndpoint.Address, TimeSpan.FromMinutes(30)); + banManager?.Ban(client.RemoteEndpoint.Address, TimeSpan.FromMinutes(3)); } break; @@ -296,7 +296,7 @@ protected virtual void OnClientError(StratumClient client, Exception ex) if (clusterConfig.Banning?.BanOnJunkReceive.HasValue == false || clusterConfig.Banning?.BanOnJunkReceive == true) { logger.Info(() => $"[{client.ConnectionId}] Banning client for failing SSL handshake"); - banManager?.Ban(client.RemoteEndpoint.Address, TimeSpan.FromMinutes(30)); + banManager?.Ban(client.RemoteEndpoint.Address, TimeSpan.FromMinutes(3)); } } break; From b6ea4d61e38e6eacaa57f29e4aabcca7425b9aef Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 23 Nov 2018 14:28:44 +0100 Subject: [PATCH 081/178] nuget update --- src/Miningcore/Miningcore.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 7e53d6cb5..102d7c6f3 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -51,19 +51,19 @@ - + - + - + From 419fafd52d7347af9a3d057e004adeafb8e65b7d Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 23 Nov 2018 15:18:38 +0100 Subject: [PATCH 082/178] Added some prometheus metrics --- src/Miningcore/AutofacModule.cs | 7 ++- src/Miningcore/Mining/BtStreamReceiver.cs | 3 +- .../Notifications/Messages/BtStreamMessage.cs | 10 ++- .../Notifications/Messages/TelemetryEvent.cs | 1 - .../Notifications/MetricsPublisher.cs | 62 +++++++++++++++++++ src/Miningcore/Program.cs | 5 ++ 6 files changed, 82 insertions(+), 6 deletions(-) create mode 100644 src/Miningcore/Notifications/MetricsPublisher.cs diff --git a/src/Miningcore/AutofacModule.cs b/src/Miningcore/AutofacModule.cs index 0127b5398..cc165b755 100644 --- a/src/Miningcore/AutofacModule.cs +++ b/src/Miningcore/AutofacModule.cs @@ -93,11 +93,14 @@ protected override void Load(ContainerBuilder builder) .SingleInstance(); builder.RegisterType() - .AsSelf(); - + .SingleInstance(); + builder.RegisterType() .SingleInstance(); + builder.RegisterType() + .SingleInstance(); + builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()) .Where(t => t.GetCustomAttributes().Any() && t.GetInterfaces() .Any(i => diff --git a/src/Miningcore/Mining/BtStreamReceiver.cs b/src/Miningcore/Mining/BtStreamReceiver.cs index 1a3d98b66..9d5da27bc 100644 --- a/src/Miningcore/Mining/BtStreamReceiver.cs +++ b/src/Miningcore/Mining/BtStreamReceiver.cs @@ -140,6 +140,7 @@ private void ProcessMessage(ZMessage msg) var topic = msg[0].ToString(Encoding.UTF8); var flags = msg[1].ReadUInt32(); var data = msg[2].Read(); + var sent = DateTimeOffset.FromUnixTimeMilliseconds(msg[3].ReadInt64()).DateTime; // TMP FIX if (flags != 0 && ((flags & 1) == 0)) @@ -166,7 +167,7 @@ private void ProcessMessage(ZMessage msg) var content = Encoding.UTF8.GetString(data); // publish - messageBus.SendMessage(new BtStreamMessage(topic, content)); + messageBus.SendMessage(new BtStreamMessage(topic, content, sent, DateTime.UtcNow)); } #region API-Surface diff --git a/src/Miningcore/Notifications/Messages/BtStreamMessage.cs b/src/Miningcore/Notifications/Messages/BtStreamMessage.cs index 67fc1dde1..ef33ec5d6 100644 --- a/src/Miningcore/Notifications/Messages/BtStreamMessage.cs +++ b/src/Miningcore/Notifications/Messages/BtStreamMessage.cs @@ -1,14 +1,20 @@ -namespace Miningcore.Notifications.Messages +using System; + +namespace Miningcore.Notifications.Messages { public class BtStreamMessage { - public BtStreamMessage(string topic, string payload) + public BtStreamMessage(string topic, string payload, DateTime sent, DateTime received) { Topic = topic; Payload = payload; + Sent = sent; + Received = received; } public string Topic { get; } public string Payload { get; } + public DateTime Sent { get; } + public DateTime Received { get; } } } diff --git a/src/Miningcore/Notifications/Messages/TelemetryEvent.cs b/src/Miningcore/Notifications/Messages/TelemetryEvent.cs index 3cd4e2be3..28d9a5f22 100644 --- a/src/Miningcore/Notifications/Messages/TelemetryEvent.cs +++ b/src/Miningcore/Notifications/Messages/TelemetryEvent.cs @@ -7,7 +7,6 @@ namespace Miningcore.Notifications.Messages public enum TelemetryCategory { Share = 1, // Share processed - BtStream, // Blocktemplate over BTStream RpcRequest // JsonRPC Request to Daemon } diff --git a/src/Miningcore/Notifications/MetricsPublisher.cs b/src/Miningcore/Notifications/MetricsPublisher.cs new file mode 100644 index 000000000..a3215b312 --- /dev/null +++ b/src/Miningcore/Notifications/MetricsPublisher.cs @@ -0,0 +1,62 @@ +using System; +using Miningcore.Configuration; +using Miningcore.Messaging; +using Miningcore.Notifications.Messages; +using Prometheus; + +namespace Miningcore.Notifications +{ + public class MetricsPublisher + { + public MetricsPublisher(IMessageBus messageBus) + { + CreateMetrics(); + + messageBus.Listen().Subscribe(OnBtStreamMessage); + messageBus.Listen().Subscribe(OnTelemetryEvent); + } + + private Summary btStreamLatencySummary; + private Counter shareCounter; + private Summary rpcRequestDurationSummary; + + private void CreateMetrics() + { + btStreamLatencySummary = Metrics.CreateSummary("miningcore_btstream_latency", "Latency of streaming block-templates in ms", new SummaryConfiguration + { + LabelNames = new[] { "topic" } + }); + + shareCounter = Metrics.CreateCounter("miningcore_valid_shares_total", "Valid received shares per pool", new CounterConfiguration + { + LabelNames = new[] { "poolId" } + }); + + rpcRequestDurationSummary = Metrics.CreateSummary("miningcore_rpcrequest_execution_time", "Duration of RPC requests ms", new SummaryConfiguration + { + LabelNames = new[] { "poolId", "method" } + }); + } + + private void OnBtStreamMessage(BtStreamMessage msg) + { + var latency = msg.Received - msg.Sent; + + btStreamLatencySummary.WithLabels(msg.Topic).Observe(latency.TotalMilliseconds); + } + + private void OnTelemetryEvent(TelemetryEvent msg) + { + switch(msg.Category) + { + case TelemetryCategory.Share: + shareCounter.WithLabels(msg.PoolId).Inc(); + break; + + case TelemetryCategory.RpcRequest: + rpcRequestDurationSummary.WithLabels(msg.PoolId, msg.Info).Observe(msg.Elapsed.TotalMilliseconds); + break; + } + } + } +} diff --git a/src/Miningcore/Program.cs b/src/Miningcore/Program.cs index b0a5e651a..a3c752d6d 100644 --- a/src/Miningcore/Program.cs +++ b/src/Miningcore/Program.cs @@ -93,6 +93,7 @@ public class Program private static ClusterConfig clusterConfig; private static IWebHost webHost; private static NotificationService notificationService; + private static MetricsPublisher metricsPublisher; private static BtStreamReceiver btStreamReceiver; private static readonly ConcurrentDictionary pools = new ConcurrentDictionary(); @@ -798,8 +799,12 @@ private static async Task Start() // start API if (clusterConfig.Api == null || clusterConfig.Api.Enabled) + { StartApi(); + metricsPublisher = container.Resolve(); + } + // start payment processor if (clusterConfig.PaymentProcessing?.Enabled == true && clusterConfig.Pools.Any(x => x.PaymentProcessing?.Enabled == true)) From bf4b5a238241b7900f7f1c5d4a459e350f4cd6b7 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 23 Nov 2018 16:06:32 +0100 Subject: [PATCH 083/178] Metrics refactor --- src/Miningcore/Blockchain/JobManagerBase.cs | 2 ++ .../Extensions/ObservableExtensions.cs | 17 +++++++++++++++++ .../Notifications/Messages/TelemetryEvent.cs | 1 + .../Notifications/MetricsPublisher.cs | 18 +++++++----------- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/Miningcore/Blockchain/JobManagerBase.cs b/src/Miningcore/Blockchain/JobManagerBase.cs index 811afe6c7..3a93a52af 100644 --- a/src/Miningcore/Blockchain/JobManagerBase.cs +++ b/src/Miningcore/Blockchain/JobManagerBase.cs @@ -99,6 +99,8 @@ protected IObservable BtStreamSubscribe(ZmqPubSubEndpointConfig config) { return messageBus.Listen() .Where(x => x.Topic == config.Topic) + .DoSafe(x => messageBus.SendMessage(new TelemetryEvent( + clusterConfig.ClusterName, poolConfig.Id, TelemetryCategory.BtStream, x.Received - x.Sent)), logger) .Select(x => x.Payload) .Publish() .RefCount(); diff --git a/src/Miningcore/Extensions/ObservableExtensions.cs b/src/Miningcore/Extensions/ObservableExtensions.cs index 47dcc8a5c..f3e7912b6 100644 --- a/src/Miningcore/Extensions/ObservableExtensions.cs +++ b/src/Miningcore/Extensions/ObservableExtensions.cs @@ -18,6 +18,7 @@ portions of the Software. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +using NLog; using System; using System.Reactive.Disposables; using System.Reactive.Linq; @@ -59,5 +60,21 @@ public static IObservable Spy(this IObservable source, string opName = } }); } + + public static IObservable DoSafe(this IObservable source, Action action, ILogger logger) + { + return source.Do(x => + { + try + { + action(x); + } + + catch(Exception ex) + { + logger.Error(ex); + } + }); + } } } diff --git a/src/Miningcore/Notifications/Messages/TelemetryEvent.cs b/src/Miningcore/Notifications/Messages/TelemetryEvent.cs index 28d9a5f22..3cd4e2be3 100644 --- a/src/Miningcore/Notifications/Messages/TelemetryEvent.cs +++ b/src/Miningcore/Notifications/Messages/TelemetryEvent.cs @@ -7,6 +7,7 @@ namespace Miningcore.Notifications.Messages public enum TelemetryCategory { Share = 1, // Share processed + BtStream, // Blocktemplate over BTStream RpcRequest // JsonRPC Request to Daemon } diff --git a/src/Miningcore/Notifications/MetricsPublisher.cs b/src/Miningcore/Notifications/MetricsPublisher.cs index a3215b312..83f256141 100644 --- a/src/Miningcore/Notifications/MetricsPublisher.cs +++ b/src/Miningcore/Notifications/MetricsPublisher.cs @@ -12,7 +12,6 @@ public MetricsPublisher(IMessageBus messageBus) { CreateMetrics(); - messageBus.Listen().Subscribe(OnBtStreamMessage); messageBus.Listen().Subscribe(OnTelemetryEvent); } @@ -24,27 +23,20 @@ private void CreateMetrics() { btStreamLatencySummary = Metrics.CreateSummary("miningcore_btstream_latency", "Latency of streaming block-templates in ms", new SummaryConfiguration { - LabelNames = new[] { "topic" } + LabelNames = new[] { "pool" } }); shareCounter = Metrics.CreateCounter("miningcore_valid_shares_total", "Valid received shares per pool", new CounterConfiguration { - LabelNames = new[] { "poolId" } + LabelNames = new[] { "pool" } }); rpcRequestDurationSummary = Metrics.CreateSummary("miningcore_rpcrequest_execution_time", "Duration of RPC requests ms", new SummaryConfiguration { - LabelNames = new[] { "poolId", "method" } + LabelNames = new[] { "pool", "method" } }); } - private void OnBtStreamMessage(BtStreamMessage msg) - { - var latency = msg.Received - msg.Sent; - - btStreamLatencySummary.WithLabels(msg.Topic).Observe(latency.TotalMilliseconds); - } - private void OnTelemetryEvent(TelemetryEvent msg) { switch(msg.Category) @@ -53,6 +45,10 @@ private void OnTelemetryEvent(TelemetryEvent msg) shareCounter.WithLabels(msg.PoolId).Inc(); break; + case TelemetryCategory.BtStream: + btStreamLatencySummary.WithLabels(msg.PoolId).Observe(msg.Elapsed.TotalMilliseconds); + break; + case TelemetryCategory.RpcRequest: rpcRequestDurationSummary.WithLabels(msg.PoolId, msg.Info).Observe(msg.Elapsed.TotalMilliseconds); break; From 570afc778d31c4a18f8bb77c09945c88096a9aaf Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 23 Nov 2018 17:11:56 +0100 Subject: [PATCH 084/178] Improve API IP access whitelist handling --- .../Middlewares/IPAccessWhitelistMiddleware.cs | 2 +- src/Miningcore/Program.cs | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Miningcore/Api/Middlewares/IPAccessWhitelistMiddleware.cs b/src/Miningcore/Api/Middlewares/IPAccessWhitelistMiddleware.cs index 7b66f2c89..22c7d609b 100644 --- a/src/Miningcore/Api/Middlewares/IPAccessWhitelistMiddleware.cs +++ b/src/Miningcore/Api/Middlewares/IPAccessWhitelistMiddleware.cs @@ -33,7 +33,7 @@ public async Task Invoke(HttpContext context) logger.Info(() => $"Unauthorized request attempt to {context.Request.Path.Value} from {remoteAddress}"); context.Response.StatusCode = (int)HttpStatusCode.Forbidden; - await context.Response.WriteAsync("You are not in my access list. Good Bye."); + await context.Response.WriteAsync("You are not in my access list. Good Bye.\n"); return; } } diff --git a/src/Miningcore/Program.cs b/src/Miningcore/Program.cs index a3c752d6d..32ce27d75 100644 --- a/src/Miningcore/Program.cs +++ b/src/Miningcore/Program.cs @@ -624,12 +624,20 @@ private static Dictionary LoadCoinTemplates() private static void UseIpWhiteList(IApplicationBuilder app, bool defaultToLoopback, string[] locations, string[] whitelist) { - var ipList = whitelist?.Select(x => IPAddress.Parse(x)).ToArray(); - if (defaultToLoopback && (ipList == null || ipList.Length == 0)) - ipList = new[] { IPAddress.Loopback, IPAddress.IPv6Loopback, IPUtils.IPv4LoopBackOnIPv6 }; + var ipList = whitelist?.Select(x => IPAddress.Parse(x)).ToList(); + if (defaultToLoopback || ipList == null || ipList.Count == 0) + ipList = new List(new[] { IPAddress.Loopback, IPAddress.IPv6Loopback, IPUtils.IPv4LoopBackOnIPv6 }); - if (ipList?.Length > 0) + if (ipList.Count > 0) { + // always allow access by localhost + if (!ipList.Any(x => x.Equals(IPAddress.Loopback))) + ipList.Add(IPAddress.Loopback); + if (!ipList.Any(x => x.Equals(IPAddress.IPv6Loopback))) + ipList.Add(IPAddress.IPv6Loopback); + if (!ipList.Any(x => x.Equals(IPUtils.IPv4LoopBackOnIPv6))) + ipList.Add(IPUtils.IPv4LoopBackOnIPv6); + logger.Info(() => $"API Access to {string.Join(",", locations)} restricted to {string.Join(",", ipList.Select(x=> x.ToString()))}"); app.UseMiddleware(locations, ipList); From 3efa1885d0f2982b18e5e0259d1a4094f7ebc524 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 23 Nov 2018 20:06:38 +0100 Subject: [PATCH 085/178] WIP --- src/Miningcore/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Program.cs b/src/Miningcore/Program.cs index b0a5e651a..84df966fc 100644 --- a/src/Miningcore/Program.cs +++ b/src/Miningcore/Program.cs @@ -631,7 +631,7 @@ private static void UseIpWhiteList(IApplicationBuilder app, bool defaultToLoopba { logger.Info(() => $"API Access to {string.Join(",", locations)} restricted to {string.Join(",", ipList.Select(x=> x.ToString()))}"); - app.UseMiddleware(locations, ipList); + app.UseMiddleware(locations, ipList.ToArray()); } } From ebee2a9cc5d6760bb55a9b870cd07700c969f9f7 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 23 Nov 2018 20:18:12 +0100 Subject: [PATCH 086/178] WIP --- src/Miningcore/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Program.cs b/src/Miningcore/Program.cs index 726d3cfe6..463d3c03f 100644 --- a/src/Miningcore/Program.cs +++ b/src/Miningcore/Program.cs @@ -625,7 +625,7 @@ private static Dictionary LoadCoinTemplates() private static void UseIpWhiteList(IApplicationBuilder app, bool defaultToLoopback, string[] locations, string[] whitelist) { var ipList = whitelist?.Select(x => IPAddress.Parse(x)).ToList(); - if (defaultToLoopback || ipList == null || ipList.Count == 0) + if (defaultToLoopback && (ipList == null || ipList.Count == 0)) ipList = new List(new[] { IPAddress.Loopback, IPAddress.IPv6Loopback, IPUtils.IPv4LoopBackOnIPv6 }); if (ipList.Count > 0) From 400c25bf3034889d4cf3082f8ba786c45b47ce89 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 28 Nov 2018 11:16:04 +0100 Subject: [PATCH 087/178] Threads -> Tasks --- src/Miningcore/Mining/StatsRecorder.cs | 23 +++++++---------------- src/Miningcore/Payments/PayoutManager.cs | 20 +++++--------------- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/src/Miningcore/Mining/StatsRecorder.cs b/src/Miningcore/Mining/StatsRecorder.cs index b92c1d56d..842dfb3a0 100644 --- a/src/Miningcore/Mining/StatsRecorder.cs +++ b/src/Miningcore/Mining/StatsRecorder.cs @@ -57,13 +57,12 @@ public StatsRecorder(IComponentContext ctx, private readonly IMessageBus messageBus; private readonly IComponentContext ctx; private readonly IShareRepository shareRepo; - private readonly AutoResetEvent stopEvent = new AutoResetEvent(false); + private readonly CancellationTokenSource cts = new CancellationTokenSource(); private readonly ConcurrentDictionary pools = new ConcurrentDictionary(); private const int HashrateCalculationWindow = 1200; // seconds private const int MinHashrateCalculationWindow = 300; // seconds private const double HashrateBoostFactor = 1.1d; private ClusterConfig clusterConfig; - private Thread thread1; private const int RetryCount = 4; private IAsyncPolicy readFaultPolicy; @@ -85,14 +84,14 @@ public void Start() { logger.Info(() => "Online"); - thread1 = new Thread(async () => - { + Task.Run(async () => + { // warm-up delay - Thread.Sleep(TimeSpan.FromSeconds(10)); + await Task.Delay(TimeSpan.FromSeconds(10)); var interval = TimeSpan.FromMinutes(5); - while(true) + while(!cts.IsCancellationRequested) { try { @@ -105,24 +104,16 @@ public void Start() logger.Error(ex); } - var waitResult = stopEvent.WaitOne(interval); - - // check if stop was signalled - if (waitResult) - break; + await Task.Delay(interval, cts.Token); } }); - - thread1.Name = "StatsRecorder"; - thread1.Start(); } public void Stop() { logger.Info(() => "Stopping .."); - stopEvent.Set(); - thread1.Join(); + cts.Cancel(); logger.Info(() => "Stopped"); } diff --git a/src/Miningcore/Payments/PayoutManager.cs b/src/Miningcore/Payments/PayoutManager.cs index 357bd33d7..c03175f33 100644 --- a/src/Miningcore/Payments/PayoutManager.cs +++ b/src/Miningcore/Payments/PayoutManager.cs @@ -71,9 +71,8 @@ public PayoutManager(IComponentContext ctx, private readonly IComponentContext ctx; private readonly IShareRepository shareRepo; private readonly IMessageBus messageBus; - private readonly AutoResetEvent stopEvent = new AutoResetEvent(false); + private readonly CancellationTokenSource cts = new CancellationTokenSource(); private ClusterConfig clusterConfig; - private Thread thread; private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); private async Task ProcessPoolsAsync() @@ -250,14 +249,14 @@ public void Configure(ClusterConfig clusterConfig) public void Start() { - thread = new Thread(async () => + Task.Run(async () => { logger.Info(() => "Online"); var interval = TimeSpan.FromSeconds( clusterConfig.PaymentProcessing.Interval > 0 ? clusterConfig.PaymentProcessing.Interval : 600); - while(true) + while (!cts.IsCancellationRequested) { try { @@ -269,25 +268,16 @@ public void Start() logger.Error(ex); } - var waitResult = stopEvent.WaitOne(interval); - - // check if stop was signalled - if (waitResult) - break; + await Task.Delay(interval, cts.Token); } }); - - thread.Priority = ThreadPriority.Highest; - thread.Name = "Payment Processing"; - thread.Start(); } public void Stop() { logger.Info(() => "Stopping .."); - stopEvent.Set(); - thread.Join(); + cts.Cancel(); logger.Info(() => "Stopped"); } From dabcd77ade91d2d574a2464a0333ad4f8a62b9bc Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 28 Nov 2018 12:27:02 +0100 Subject: [PATCH 088/178] Refactor --- src/Miningcore/Mining/StatsRecorder.cs | 9 ++++----- src/Miningcore/Payments/PayoutManager.cs | 7 ++++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Miningcore/Mining/StatsRecorder.cs b/src/Miningcore/Mining/StatsRecorder.cs index 842dfb3a0..dfd81f610 100644 --- a/src/Miningcore/Mining/StatsRecorder.cs +++ b/src/Miningcore/Mining/StatsRecorder.cs @@ -58,7 +58,8 @@ public StatsRecorder(IComponentContext ctx, private readonly IComponentContext ctx; private readonly IShareRepository shareRepo; private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly ConcurrentDictionary pools = new ConcurrentDictionary(); + private readonly ConcurrentDictionary pools = new ConcurrentDictionary(); + private readonly TimeSpan interval = TimeSpan.FromMinutes(5); private const int HashrateCalculationWindow = 1200; // seconds private const int MinHashrateCalculationWindow = 300; // seconds private const double HashrateBoostFactor = 1.1d; @@ -82,15 +83,13 @@ public void AttachPool(IMiningPool pool) public void Start() { - logger.Info(() => "Online"); - Task.Run(async () => { + logger.Info(() => "Online"); + // warm-up delay await Task.Delay(TimeSpan.FromSeconds(10)); - var interval = TimeSpan.FromMinutes(5); - while(!cts.IsCancellationRequested) { try diff --git a/src/Miningcore/Payments/PayoutManager.cs b/src/Miningcore/Payments/PayoutManager.cs index c03175f33..bde33cb3a 100644 --- a/src/Miningcore/Payments/PayoutManager.cs +++ b/src/Miningcore/Payments/PayoutManager.cs @@ -72,6 +72,7 @@ public PayoutManager(IComponentContext ctx, private readonly IShareRepository shareRepo; private readonly IMessageBus messageBus; private readonly CancellationTokenSource cts = new CancellationTokenSource(); + private TimeSpan interval; private ClusterConfig clusterConfig; private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); @@ -245,6 +246,9 @@ private async Task CalculateBlockEffortAsync(PoolConfig pool, Block block, IPayo public void Configure(ClusterConfig clusterConfig) { this.clusterConfig = clusterConfig; + + interval = TimeSpan.FromSeconds(clusterConfig.PaymentProcessing.Interval > 0 ? + clusterConfig.PaymentProcessing.Interval : 600); } public void Start() @@ -253,9 +257,6 @@ public void Start() { logger.Info(() => "Online"); - var interval = TimeSpan.FromSeconds( - clusterConfig.PaymentProcessing.Interval > 0 ? clusterConfig.PaymentProcessing.Interval : 600); - while (!cts.IsCancellationRequested) { try From 2dc2a87f55cec9cbfe96f2b90ef80e48a11074d0 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sat, 1 Dec 2018 14:06:59 +0100 Subject: [PATCH 089/178] x21s hash --- libs/runtimes/win-x64/libmultihash.dll | Bin 1183744 -> 1188352 bytes src/Miningcore.Tests/Crypto/HashingTests.cs | 11 + .../Crypto/Hashing/Algorithms/X21s.cs | 42 ++++ src/Miningcore/Native/LibMultihash.cs | 3 + src/Native/libmultihash/Makefile | 2 +- src/Native/libmultihash/exports.cpp | 6 + src/Native/libmultihash/libmultihash.vcxproj | 2 + .../libmultihash/libmultihash.vcxproj.filters | 6 + src/Native/libmultihash/x21s.c | 205 ++++++++++++++++++ src/Native/libmultihash/x21s.h | 16 ++ 10 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/X21s.cs create mode 100644 src/Native/libmultihash/x21s.c create mode 100644 src/Native/libmultihash/x21s.h diff --git a/libs/runtimes/win-x64/libmultihash.dll b/libs/runtimes/win-x64/libmultihash.dll index fb7869bcb4208ac5d93571652c5fa5a7a4667478..5d48383691af35faed2a37cf6ec72f56e25599f4 100644 GIT binary patch delta 170907 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 Khy3g=k^cwPS^O^m diff --git a/src/Miningcore.Tests/Crypto/HashingTests.cs b/src/Miningcore.Tests/Crypto/HashingTests.cs index 44c5d6deb..35abcefd3 100644 --- a/src/Miningcore.Tests/Crypto/HashingTests.cs +++ b/src/Miningcore.Tests/Crypto/HashingTests.cs @@ -213,6 +213,17 @@ public void X22I_Hash() Assert.Equal("616c341e79417e6623dacff834c5c480d8d7d43ba6ae60fcee99f69343fd7c99", result); } + [Fact] + public void X21S_Hash() + { + var hasher = new X21S(); + var hash = new byte[32]; + hasher.Digest(testValue, hash); + var result = hash.ToHexString(); + + Assert.Equal("0bfd2e20a3656b5f92079ea5c6485223b00344f9f1005ab9ecedff3c42ccf76f", result); + } + [Fact] public void Skein_Hash() { diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/X21s.cs b/src/Miningcore/Crypto/Hashing/Algorithms/X21s.cs new file mode 100644 index 000000000..9afa80ee1 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/X21s.cs @@ -0,0 +1,42 @@ +/* +Copyright 2017 Coin Foundry (coinfoundry.org) +Authors: Oliver Weichhold (oliver@weichhold.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +using System; +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms +{ + public unsafe class X21S : IHashAlgorithm + { + public void Digest(ReadOnlySpan data, Span result, params object[] extra) + { + Contract.Requires(result.Length >= 32, $"{nameof(result)} must be greater or equal 32 bytes"); + + fixed (byte* input = data) + { + fixed (byte* output = result) + { + LibMultihash.x21s(input, output, (uint) data.Length); + } + } + } + } +} diff --git a/src/Miningcore/Native/LibMultihash.cs b/src/Miningcore/Native/LibMultihash.cs index 132e29664..307de3ac7 100644 --- a/src/Miningcore/Native/LibMultihash.cs +++ b/src/Miningcore/Native/LibMultihash.cs @@ -49,6 +49,9 @@ public static unsafe class LibMultihash [DllImport("libmultihash", EntryPoint = "x22i_export", CallingConvention = CallingConvention.Cdecl)] public static extern int x22i(byte* input, void* output, uint inputLength); + [DllImport("libmultihash", EntryPoint = "x21s_export", CallingConvention = CallingConvention.Cdecl)] + public static extern int x21s(byte* input, void* output, uint inputLength); + [DllImport("libmultihash", EntryPoint = "neoscrypt_export", CallingConvention = CallingConvention.Cdecl)] public static extern int neoscrypt(byte* input, void* output, uint inputLength, uint profile); diff --git a/src/Native/libmultihash/Makefile b/src/Native/libmultihash/Makefile index 885f71f79..3817b500d 100644 --- a/src/Native/libmultihash/Makefile +++ b/src/Native/libmultihash/Makefile @@ -12,7 +12,7 @@ OBJECTS = bcrypt.o blake.o blake2s.o c11.o dcrypt.o fresh.o \ sha3/sph_luffa.o sha3/sph_shabal.o sha3/sph_shavite.o sha3/sph_simd.o sha3/sph_skein.o sha3/sph_whirlpool.o \ sha3/sph_haval.o sha3/sph_sha2.o sha3/sph_sha2big.o sha3/sph_blake2s.o sha3/sm3.o \ sha3/extra.o sha3/gost_streebog.o sha3/sph_tiger.o sha3/SWIFFTX.o \ - shavite3.o skein.o x11.o x13.o x15.o x17.o x16r.o x16s.o x22i.o \ + shavite3.o skein.o x11.o x13.o x15.o x17.o x16r.o x16s.o x22i.o x21s.o \ Lyra2.o Lyra2RE.o Sponge.o geek.o \ equi/util.o equi/support/cleanse.o equi/random.o \ equi/uint256.o equi/arith_uint256.o equi/crypto/hmac_sha512.o \ diff --git a/src/Native/libmultihash/exports.cpp b/src/Native/libmultihash/exports.cpp index 938748a0e..1492fa74b 100644 --- a/src/Native/libmultihash/exports.cpp +++ b/src/Native/libmultihash/exports.cpp @@ -46,6 +46,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "x16r.h" #include "x16s.h" #include "x22i.h" +#include "x21s.h" #include "equi/equihashverify.h" #include "libethash/sha3.h" #include "libethash/internal.h" @@ -216,6 +217,11 @@ extern "C" MODULE_API void x22i_export(const char* input, char* output, uint32_t x22i_hash(input, output, input_len); } +extern "C" MODULE_API void x21s_export(const char* input, char* output, uint32_t input_len) +{ + x21s_hash(input, output, input_len); +} + extern "C" MODULE_API void x16s_export(const char* input, char* output, uint32_t input_len) { x16s_hash(input, output, input_len); diff --git a/src/Native/libmultihash/libmultihash.vcxproj b/src/Native/libmultihash/libmultihash.vcxproj index e8b98d5aa..1e6567d3a 100644 --- a/src/Native/libmultihash/libmultihash.vcxproj +++ b/src/Native/libmultihash/libmultihash.vcxproj @@ -257,6 +257,7 @@ +
@@ -339,6 +340,7 @@ + diff --git a/src/Native/libmultihash/libmultihash.vcxproj.filters b/src/Native/libmultihash/libmultihash.vcxproj.filters index 62f73e233..2cfe7add0 100644 --- a/src/Native/libmultihash/libmultihash.vcxproj.filters +++ b/src/Native/libmultihash/libmultihash.vcxproj.filters @@ -281,6 +281,9 @@ Header Files + + Header Files + @@ -523,6 +526,9 @@ Source Files + + Source Files + diff --git a/src/Native/libmultihash/x21s.c b/src/Native/libmultihash/x21s.c new file mode 100644 index 000000000..878d9c223 --- /dev/null +++ b/src/Native/libmultihash/x21s.c @@ -0,0 +1,205 @@ +#include +#include +#include +#include + +#include "sha3/extra.h" +#include "sha3/sph_blake.h" +#include "sha3/sph_bmw.h" +#include "sha3/sph_groestl.h" +#include "sha3/sph_jh.h" +#include "sha3/sph_keccak.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_luffa.h" +#include "sha3/sph_cubehash.h" +#include "sha3/sph_shavite.h" +#include "sha3/sph_simd.h" +#include "sha3/sph_echo.h" +#include "sha3/sph_hamsi.h" +#include "sha3/sph_fugue.h" +#include "sha3/sph_shabal.h" +#include "sha3/sph_whirlpool.h" +#include "sha3/sph_sha2.h" +#include "sha3/sph_haval.h" +#include "sha3/sph_tiger.h" +#include "lyra2.h" +#include "sha3/gost_streebog.h" + +enum Algo { + BLAKE = 0, + BMW, + GROESTL, + JH, + KECCAK, + SKEIN, + LUFFA, + CUBEHASH, + SHAVITE, + SIMD, + ECHO, + HAMSI, + FUGUE, + SHABAL, + WHIRLPOOL, + SHA512, + HASH_FUNC_COUNT +}; +static void getAlgoString(const uint8_t* prevblock, char *output) +{ + strcpy(output, "0123456789ABCDEF"); + + for (int i = 0; i < 16; i++) { + uint8_t b = (15 - i) >> 1; // 16 ascii hex chars, reversed + uint8_t algoDigit = (i & 1) ? prevblock[b] & 0xF : prevblock[b] >> 4; + + int offset = algoDigit; + // insert the nth character at the front + char oldVal = output[offset]; + for (int j = offset; j-- > 0;) { + output[j + 1] = output[j]; + } + output[0] = oldVal; + } +} + +void x21s_hash(const char* input, char* output, uint32_t len) { + uint32_t hash[64 / 4]; + char hashOrder[HASH_FUNC_COUNT + 1] = { 0 }; + + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_skein512_context ctx_skein; + sph_luffa512_context ctx_luffa; + sph_cubehash512_context ctx_cubehash; + sph_shavite512_context ctx_shavite; + sph_simd512_context ctx_simd; + sph_echo512_context ctx_echo; + sph_hamsi512_context ctx_hamsi; + sph_fugue512_context ctx_fugue; + sph_shabal512_context ctx_shabal; + sph_whirlpool_context ctx_whirlpool; + sph_sha512_context ctx_sha512; + sph_haval256_5_context ctx_haval; + sph_tiger_context ctx_tiger; + sph_gost512_context ctx_gost; + sph_sha256_context ctx_sha; + + void *in = (void*)input; + int size = len; + + getAlgoString(&input[4], hashOrder); + + for (int i = 0; i < 16; i++) + { + const char elem = hashOrder[i]; + const uint8_t algo = elem >= 'A' ? elem - 'A' + 10 : elem - '0'; + + switch (algo) { + case BLAKE: + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, in, size); + sph_blake512_close(&ctx_blake, hash); + break; + case BMW: + sph_bmw512_init(&ctx_bmw); + sph_bmw512(&ctx_bmw, in, size); + sph_bmw512_close(&ctx_bmw, hash); + break; + case GROESTL: + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, in, size); + sph_groestl512_close(&ctx_groestl, hash); + break; + case SKEIN: + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, in, size); + sph_skein512_close(&ctx_skein, hash); + break; + case JH: + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, in, size); + sph_jh512_close(&ctx_jh, hash); + break; + case KECCAK: + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, in, size); + sph_keccak512_close(&ctx_keccak, hash); + break; + case LUFFA: + sph_luffa512_init(&ctx_luffa); + sph_luffa512(&ctx_luffa, in, size); + sph_luffa512_close(&ctx_luffa, hash); + break; + case CUBEHASH: + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512(&ctx_cubehash, in, size); + sph_cubehash512_close(&ctx_cubehash, hash); + break; + case SHAVITE: + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, in, size); + sph_shavite512_close(&ctx_shavite, hash); + break; + case SIMD: + sph_simd512_init(&ctx_simd); + sph_simd512(&ctx_simd, in, size); + sph_simd512_close(&ctx_simd, hash); + break; + case ECHO: + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, in, size); + sph_echo512_close(&ctx_echo, hash); + break; + case HAMSI: + sph_hamsi512_init(&ctx_hamsi); + sph_hamsi512(&ctx_hamsi, in, size); + sph_hamsi512_close(&ctx_hamsi, hash); + break; + case FUGUE: + sph_fugue512_init(&ctx_fugue); + sph_fugue512(&ctx_fugue, in, size); + sph_fugue512_close(&ctx_fugue, hash); + break; + case SHABAL: + sph_shabal512_init(&ctx_shabal); + sph_shabal512(&ctx_shabal, in, size); + sph_shabal512_close(&ctx_shabal, hash); + break; + case WHIRLPOOL: + sph_whirlpool_init(&ctx_whirlpool); + sph_whirlpool(&ctx_whirlpool, in, size); + sph_whirlpool_close(&ctx_whirlpool, hash); + break; + case SHA512: + sph_sha512_init(&ctx_sha512); + sph_sha512(&ctx_sha512, (const void*)in, size); + sph_sha512_close(&ctx_sha512, (void*)hash); + break; + } + in = (void*)hash; + size = 64; + } + + sph_haval256_5_init(&ctx_haval); + sph_haval256_5(&ctx_haval, (const void*)hash, 64); + sph_haval256_5_close(&ctx_haval, hash); + + sph_tiger_init(&ctx_tiger); + sph_tiger(&ctx_tiger, (const void*)hash, 64); + sph_tiger_close(&ctx_tiger, (void*)hash); + + LYRA2((void*)hash, 32, (const void*)hash, 32, (const void*)hash, 32, 1, 4, 4); + + sph_gost512_init(&ctx_gost); + sph_gost512(&ctx_gost, (const void*)hash, 64); + sph_gost512_close(&ctx_gost, (void*)hash); + + sph_sha256_init(&ctx_sha); + sph_sha256(&ctx_sha, (const void*)hash, 64); + sph_sha256_close(&ctx_sha, (void*)hash); + + memcpy(output, hash, 32); +} diff --git a/src/Native/libmultihash/x21s.h b/src/Native/libmultihash/x21s.h new file mode 100644 index 000000000..2f26a7ea3 --- /dev/null +++ b/src/Native/libmultihash/x21s.h @@ -0,0 +1,16 @@ +#ifndef X21S_H +#define X21S_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void x21s_hash(const char* input, char* output, uint32_t len); + +#ifdef __cplusplus +} +#endif + +#endif From 470239ac709e85b1d2dd4609372a87ecfa4fa327 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sat, 1 Dec 2018 14:29:56 +0100 Subject: [PATCH 090/178] Build fix --- src/Native/libmultihash/x21s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Native/libmultihash/x21s.c b/src/Native/libmultihash/x21s.c index 878d9c223..9646d1d72 100644 --- a/src/Native/libmultihash/x21s.c +++ b/src/Native/libmultihash/x21s.c @@ -22,7 +22,7 @@ #include "sha3/sph_sha2.h" #include "sha3/sph_haval.h" #include "sha3/sph_tiger.h" -#include "lyra2.h" +#include "Lyra2.h" #include "sha3/gost_streebog.h" enum Algo { From 29c8d2a012c5050ed6c87744c05ab83084f0fa1a Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Thu, 6 Dec 2018 15:59:10 +0100 Subject: [PATCH 091/178] WIP --- src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs | 4 +++- .../Blockchain/Cryptonote/CryptonoteJobManager.cs | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs index 3838bd7ce..cc8c78b75 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs @@ -36,7 +36,7 @@ namespace Miningcore.Blockchain.Cryptonote public class CryptonoteJob { public CryptonoteJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, string jobId, - PoolConfig poolConfig, ClusterConfig clusterConfig) + PoolConfig poolConfig, ClusterConfig clusterConfig, string prevHash) { Contract.RequiresNonNull(blockTemplate, nameof(blockTemplate)); Contract.RequiresNonNull(poolConfig, nameof(poolConfig)); @@ -47,6 +47,7 @@ public CryptonoteJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, coin = poolConfig.Template.As(); BlockTemplate = blockTemplate; PrepareBlobTemplate(instanceId); + PrevHash = prevHash; switch (coin.Hash) { @@ -120,6 +121,7 @@ private void ComputeBlockHash(ReadOnlySpan blobConverted, Span resul #region API-Surface + public string PrevHash { get; } public GetBlockTemplateResponse BlockTemplate { get; } public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out string target) diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs index e9d65626e..c0b429715 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs @@ -44,6 +44,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using Miningcore.Stratum; using Miningcore.Time; using Miningcore.Util; +using MoreLinq; using Newtonsoft.Json; using NLog; using Contract = Miningcore.Contracts.Contract; @@ -98,8 +99,9 @@ protected async Task UpdateJob(string via = null, string json = null) var blockTemplate = response.Response; var job = currentJob; + var newHash = blockTemplate.Blob.HexToByteArray().Slice(7, 32).ToHexString(); - var isNew = job == null || job.BlockTemplate.Height < blockTemplate.Height; + var isNew = job == null || newHash != job.PrevHash; if (isNew) { @@ -110,7 +112,7 @@ protected async Task UpdateJob(string via = null, string json = null) else logger.Info(() => $"Detected new block {blockTemplate.Height}"); - job = new CryptonoteJob(blockTemplate, instanceId, NextJobId(), poolConfig, clusterConfig); + job = new CryptonoteJob(blockTemplate, instanceId, NextJobId(), poolConfig, clusterConfig, newHash); currentJob = job; // update stats From 03307435b7ecd433a00e7163a7a4cea573f474a2 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Thu, 6 Dec 2018 16:25:56 +0100 Subject: [PATCH 092/178] WIP --- .../Blockchain/Cryptonote/CryptonoteJobTests.cs | 6 +++--- src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Miningcore.Tests/Blockchain/Cryptonote/CryptonoteJobTests.cs b/src/Miningcore.Tests/Blockchain/Cryptonote/CryptonoteJobTests.cs index b22a5ed6a..6b5226977 100644 --- a/src/Miningcore.Tests/Blockchain/Cryptonote/CryptonoteJobTests.cs +++ b/src/Miningcore.Tests/Blockchain/Cryptonote/CryptonoteJobTests.cs @@ -35,7 +35,7 @@ public void MoneroJob_PrepareWorkerJob() var bt = JsonConvert.DeserializeObject( "{\"blocktemplate_blob\":\"0106e7eabdcf058234351e2e6ea901a56b33bb531587424321873072d80a9e97295b6c43152b9d00000000019c0201ffe00106e3a1a0cc010275d92c0a057aa5f073079694a153d426f837f49fdb9654da10a5364e79a2086280a0d9e61d028b46dca0d04998500b40b046fd6f8bb33229e6380fd465dbb1327aa6f813d8bd80c0fc82aa0202372f076459e769116d604d30aabff7160782acc0d20e0c5cdc8963ed4e16372f8090cad2c60e02f009504ce65538bbb684b466b21be3a90e3740f185d7089d37b75f0cf62b6e7680e08d84ddcb0102cf01b85c0b592bb6e508e20b5d317052b75de121908390363201abff3476ef0180c0caf384a302024b81076c8ad0cfe84cc32fe0813d63cdd0f7d8d0e56d82aa3f58cbbe49d4c61e2b017aaf3074be7ecb30a769595758e4da7c7c87ead864baf89b679b73153dfa352c0208000000000000000000\",\"Difficulty\":2,\"Height\":224,\"prev_hash\":\"8234351e2e6ea901a56b33bb531587424321873072d80a9e97295b6c43152b9d\",\"reserved_offset\":322,\"Status\":\"OK\"}"); - var job = new CryptonoteJob(bt, "d150da".HexToByteArray(), "1", poolConfig, clusterConfig); + var job = new CryptonoteJob(bt, "d150da".HexToByteArray(), "1", poolConfig, clusterConfig, ""); var workerJob = new CryptonoteWorkerJob(1.ToString(), 10000); job.PrepareWorkerJob(workerJob, out var blob, out var target); @@ -57,7 +57,7 @@ public void MoneroJob_Should_Accept_Valid_Share() var bt = JsonConvert.DeserializeObject( "{\"blocktemplate_blob\":\"0106e7eabdcf058234351e2e6ea901a56b33bb531587424321873072d80a9e97295b6c43152b9d00000000019c0201ffe00106e3a1a0cc010275d92c0a057aa5f073079694a153d426f837f49fdb9654da10a5364e79a2086280a0d9e61d028b46dca0d04998500b40b046fd6f8bb33229e6380fd465dbb1327aa6f813d8bd80c0fc82aa0202372f076459e769116d604d30aabff7160782acc0d20e0c5cdc8963ed4e16372f8090cad2c60e02f009504ce65538bbb684b466b21be3a90e3740f185d7089d37b75f0cf62b6e7680e08d84ddcb0102cf01b85c0b592bb6e508e20b5d317052b75de121908390363201abff3476ef0180c0caf384a302024b81076c8ad0cfe84cc32fe0813d63cdd0f7d8d0e56d82aa3f58cbbe49d4c61e2b017aaf3074be7ecb30a769595758e4da7c7c87ead864baf89b679b73153dfa352c0208000000000000000000\",\"Difficulty\":2,\"Height\":224,\"prev_hash\":\"8234351e2e6ea901a56b33bb531587424321873072d80a9e97295b6c43152b9d\",\"reserved_offset\":322,\"Status\":\"OK\"}"); - var job = new CryptonoteJob(bt, "d150da".HexToByteArray(), "1", poolConfig, clusterConfig); + var job = new CryptonoteJob(bt, "d150da".HexToByteArray(), "1", poolConfig, clusterConfig, ""); var (share, blobHex) = job.ProcessShare("040100a4", 1, "f29c7fbf57d97eeedb61555857d7a34314250da20742b8157f96e0be89530a00", worker); Assert.NotNull(share); @@ -81,7 +81,7 @@ public void MoneroJob_Should_Not_Accept_Invalid_Share() var bt = JsonConvert.DeserializeObject( "{\"blocktemplate_blob\":\"0106e7eabdcf058234351e2e6ea901a56b33bb531587424321873072d80a9e97295b6c43152b9d00000000019c0201ffe00106e3a1a0cc010275d92c0a057aa5f073079694a153d426f837f49fdb9654da10a5364e79a2086280a0d9e61d028b46dca0d04998500b40b046fd6f8bb33229e6380fd465dbb1327aa6f813d8bd80c0fc82aa0202372f076459e769116d604d30aabff7160782acc0d20e0c5cdc8963ed4e16372f8090cad2c60e02f009504ce65538bbb684b466b21be3a90e3740f185d7089d37b75f0cf62b6e7680e08d84ddcb0102cf01b85c0b592bb6e508e20b5d317052b75de121908390363201abff3476ef0180c0caf384a302024b81076c8ad0cfe84cc32fe0813d63cdd0f7d8d0e56d82aa3f58cbbe49d4c61e2b017aaf3074be7ecb30a769595758e4da7c7c87ead864baf89b679b73153dfa352c0208000000000000000000\",\"Difficulty\":2,\"Height\":224,\"prev_hash\":\"8234351e2e6ea901a56b33bb531587424321873072d80a9e97295b6c43152b9d\",\"reserved_offset\":322,\"Status\":\"OK\"}"); - var job = new CryptonoteJob(bt, "d150da".HexToByteArray(), "1", poolConfig, clusterConfig); + var job = new CryptonoteJob(bt, "d150da".HexToByteArray(), "1", poolConfig, clusterConfig, ""); // invalid nonce Assert.Throws(() => diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs index 3712041d5..0ffd38224 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs @@ -284,7 +284,7 @@ private async Task OnConfigureMiningAsync(StratumClient client, Timestamped extensionParams, Dictionary result) { - var requestedBits = extensionParams[BitcoinStratumExtensions.VersionRollingBits].Value(); + //var requestedBits = extensionParams[BitcoinStratumExtensions.VersionRollingBits].Value(); uint requestedMask = BitcoinConstants.VersionRollingPoolMask; if (extensionParams.TryGetValue(BitcoinStratumExtensions.VersionRollingMask, out var requestedMaskValue)) From ef787e30ea2dc13042414be545982bb666ef6985 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 29 Jan 2019 09:17:40 +0100 Subject: [PATCH 093/178] Upgrade to Net Core 2.2 --- src/Miningcore.Tests/Miningcore.Tests.csproj | 18 ++++++++----- src/Miningcore/Miningcore.csproj | 28 ++++++++++---------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/Miningcore.Tests/Miningcore.Tests.csproj b/src/Miningcore.Tests/Miningcore.Tests.csproj index 23d05b87e..2ea5169a2 100644 --- a/src/Miningcore.Tests/Miningcore.Tests.csproj +++ b/src/Miningcore.Tests/Miningcore.Tests.csproj @@ -10,7 +10,7 @@ - netcoreapp2.1 + netcoreapp2.2 false AnyCPU Miningcore.Tests @@ -33,10 +33,14 @@ - - - - + + + + + + all + runtime; build; native; contentfiles; analyzers + @@ -52,7 +56,7 @@ - + @@ -61,7 +65,7 @@ - + diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 486958034..1cb1da0c2 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.1 + netcoreapp2.2 Miningcore Miningcore AnyCPU @@ -53,22 +53,22 @@ - - - - - - - - - - - + + + + + + + + + + + - - + + From 97cc2ce0f4f906b51220fb22d8ac8b9ac14f4614 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 29 Jan 2019 09:18:49 +0100 Subject: [PATCH 094/178] README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index bfefb063b..b907d2caa 100644 --- a/README.md +++ b/README.md @@ -53,13 +53,13 @@ This software comes with a built-in donation of 0.1% per block-reward to support ### Runtime Requirements on Windows -- [.Net Core 2.1 Runtime](https://www.microsoft.com/net/download/core) +- [.Net Core 2.2 Runtime](https://www.microsoft.com/net/download/core) - [PostgreSQL Database](https://www.postgresql.org/) - Coin Daemon (per pool) ### Runtime Requirements on Linux -- [.Net Core 2.1 SDK](https://www.microsoft.com/net/download/core) +- [.Net Core 2.2 SDK](https://www.microsoft.com/net/download/core) - [PostgreSQL Database](https://www.postgresql.org/) - Coin Daemon (per pool) - Miningcore needs to be built from source on Linux. Refer to the section further down below for instructions. @@ -110,25 +110,25 @@ $ sudo dpkg -i packages-microsoft-prod.deb $ sudo apt-get update -y $ sudo apt-get install apt-transport-https -y $ sudo apt-get update -y -$ sudo apt-get -y install dotnet-sdk-2.1 git cmake build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 +$ sudo apt-get -y install dotnet-sdk-2.2 git cmake build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 $ git clone https://github.com/coinfoundry/miningcore $ cd miningcore/src/Miningcore -$ dotnet publish -c Release --framework netcoreapp2.1 -o ../../build +$ dotnet publish -c Release --framework netcoreapp2.2 -o ../../build ``` #### Building on Windows -Download and install the [.Net Core 2.1 SDK](https://www.microsoft.com/net/download/core) +Download and install the [.Net Core 2.2 SDK](https://www.microsoft.com/net/download/core) ```dosbatch > git clone https://github.com/coinfoundry/miningcore > cd miningcore/src/Miningcore -> dotnet publish -c Release --framework netcoreapp2.1 -o ..\..\build +> dotnet publish -c Release --framework netcoreapp2.2 -o ..\..\build ``` #### Building on Windows - Visual Studio -- Download and install the [.Net Core 2.1 SDK](https://www.microsoft.com/net/download/core) +- Download and install the [.Net Core 2.2 SDK](https://www.microsoft.com/net/download/core) - Install [Visual Studio 2017](https://www.visualstudio.com/vs/). Visual Studio Community Edition is fine. - Open `Miningcore.sln` in VS 2017 From 47ab0e6a2ae2c33629d3c000b65be5d0fba6c66d Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 29 Jan 2019 09:31:21 +0100 Subject: [PATCH 095/178] Lyra3 support --- libs/runtimes/win-x64/libmultihash.dll | Bin 1188352 -> 1189376 bytes src/Miningcore.Tests/Crypto/HashingTests.cs | 18 ++ .../Crypto/Hashing/Algorithms/Lyra2Rev3.cs | 43 ++++ src/Miningcore/Native/LibMultihash.cs | 3 + src/Native/libmultihash/Lyra2.c | 191 ++++++++++++++++++ src/Native/libmultihash/Lyra2.h | 2 + src/Native/libmultihash/Lyra2RE.c | 27 +++ src/Native/libmultihash/Lyra2RE.h | 1 + src/Native/libmultihash/exports.cpp | 5 + 9 files changed, 290 insertions(+) create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/Lyra2Rev3.cs diff --git a/libs/runtimes/win-x64/libmultihash.dll b/libs/runtimes/win-x64/libmultihash.dll index 5d48383691af35faed2a37cf6ec72f56e25599f4..feda36a76d910c35a3363006447934e78d939f2b 100644 GIT binary patch delta 82755 zcmaHU2Uru$^Dwu$To8x>6~RUm1q%uy3JMAe7!(x6f?~mrioF+_h>9_ap15|gcTrIe zJNB;l+OT&Guf1dCo87%oe1HGX=OK4fc4l^VW_E9{n0Qi~cu||?%b70lYn@;j*tlWm zT0N#2|0V?Wjtd5OLQwa(-t^cf?jsz9us(79>9KcQJ9_LM*9(qs0(-~xfa8RqC<=G3 z6*bKb;M1X<;*|8*Bd!ZQZkWc7kreJUq<;+P^qgiQ{|gT?F&QvZFv%_--qVPCZ{p-& zj>=n_yfrg18KI)+>g&a3T<>xYd#y|kDNRi7iEFru+W+ z$vKlT@D0c~xs0|MZj|9LSDeScM}KaKiOM0UVs_RmK2&z;3`UMsC{*5FI{_5R4j#IP<@Jm@8&2lvJBCbiL^ z(c+{gn=9TMqXdEJC35es6g`{nu(S9rm}t)gIy?A-e~K08GXOH=YQ#TH?^JYNr7TfF zOnSOceC0hBHEwB}A|S-7~j`9O4Vi&)LKI@Xn&Rcfl|Ophh@jPdNwCyS+aO941a_-?>u!FjJGSC%AFy1GdmD zt?r89qM!Jr{ZKS&sMx-PZM7G^WWY}PN1f2>l?%4PP^WU*XwXx&a^XS zsFO0v6g;oh^)z$#2PeAsDewywuSU3`o!$#O&p``2igPm4`r7$mOm(!A=*>tNz5i^(v?A-0C2 zO^Cr@tRdyP_`OSYgqw&qT{F>?5bsJQp~j#iHAo88x8}4k z9J;dxuL0t@Zue1(hvMeQ+Lhw_8iT{t7#yDBlgKeBzn$2%dwXQ+DQ@h35$zl*j_VO@ zF(;Hc-QCc0sCc?Zf0XPY){AO@B0R*Xs1vA@yXeq!pT)?wjLX{)5Fl&9}RU%tGB*=&XR_JgW=4Zq9Q;<7PB0XS-uvttY<7<#VlB6F+XpVlEhdl z6tj$zSzLid%o(7zco$%_p<}dob%2e<#bQK*=&a8J>=5eFJ*(2-91cBdE?$nwL8qO> z*+c5oSNM^JVbO*`QOx!qr-)WSbTm-YpZLlQK~duUA&V@UHzT7A0R^Ffk3BDECoUh_ z2%R}6UK#3$)}IqU4)sJM&tQvtparw`iih*mQVf6ksn7A6}*UX*(GCIUKu?&Cz_6Eh59jQ`Z;mHh`tWnYLL)8 zt4+xr*G-$8>!MA5^hlekEqn#Re#M}#AwD1BjQV#J%}3gygJ;EhBi)hX!K_{*m+)w+ zt@v$hZ4_ZE+K+QX&bDIvagIpeMjSnE8Cqi_s>cVT1;@oM<0qiUmBmZrTcI1rM5_rO z&|0@FexenJUbYr(CLKX8t;JiDexv*f;?2oUXm4Hd$K;l1Yz49Tl%}Xz1##Sz0oK>+ z6vxUaIaZEYiEpNOp*dEf^HhIpZ3#oP%;04uPM%s9adombOx1Fzk4AhqZ5P^qP+Su? z8?|ngRWII?LvJm_=!7e%&VGu`YMFH~u_1^0nE}>4tNQfv9C9j`RX-U#k4&>dXV`Mc zAY=_n0r;#kYv#;zNbwt)ik(s;(eWlwCF2#r0J_a_R5-!09qzSEt7v>yzjbXy{Sp4?omzy=*^(i zpreL18^}1BYO=Z6K}WUvE=S2MFlK$$XHn0gskKF6e(kI+>1P$_?ne+{CoWi84TUPj zol9q<5oV(IvS#Sc2XWjo(R#=S6$r}r%q68awYBMP&Tv2wt1mxet$+U?$^)fXxIDM= zNj(WsT?Yrl0r||;uuCsqUQrF5cqhJEQPX1t;Gt4E7zVNvS6b@|x&Z|Bj{K7s3h9e1 zO$?7XQ?cdBFog+tY5qzF#eIPHtgNeW2l(O228yE!Q_*r&J>>OP^jj5%&I{t)RW3e{ z5z$c*I$qStRGV63a$k~2bDeX*M+R8=0TE`Bxz4#H0$?&3@4#oFht^fZgL@is&qec15iS#2{6|JIEY_GM-GN9f zxwJ$~*>n|keFie@#MCXmW{<&AV$H{=;-Ss$(1xdCxh-u`fKKePWfFS$M9kb5X!isL zJhiDdbt1TPqNOGq+^3%eD=XqXm|d*0Yj+^yZJ14l(J-C&1;*_oJ}KS$(%v;Z%(hRVD#BzGB~;id=%2zWp6?eJIY{aUQL( z&FZuh#^UNd@qT8o%Wkj#c;LuFqX!lNk$Au~O>Dbs82WZsY_X?gEX2EXEIfBlbg2sy zJCWhhb->Uu~>ejA$MDRwI{-5aijmpSU2A&V=@ql zj5l+|fmv74gnT*{L-v)7MTLBET5c$JODx#i7WGXKz4lE)MK{Iy#{%tc{*R$Zl!wCa zrugAl?G8y~C^p0IMZ;S9yMkgC)AKZXK8OC!puh3-cM|;_Lw{rG?;!dcog~i8-j9ag z$O@3EaMe1EBSX=IM7lnmEUvYBeJ%<0{bR-PId4(OHF4nn3+RwVR-*$jFdy>7!v}+1 zu0q-U%cT!y8r`uMh{PSPGsL=wh9R3g(e6mez+_#a15@$vM3=U%|B=!y#VExMh(yYo z>EiCg!%*5~kkSv;zf1?_?#2e_=_T>PkqDRU+W!%9BH1WpDG-Seb&?o#^eS3>k&aBr zv67K#bWvQfw;g(ZK|Gh+7A1`pt&dGY_7^})Yx_Ir|Hs%E)1=pV(PL|^@XO=L;GBiu zi-zO$_YlQo)AL>Qd@KE3Pk&d@-zD^SA^n|8e`nI)#PL~!j{70RJrXyZ{DH2X7T26| zLOV{2r%u(YV(}Hqny!s0tSPv#dZ)E|3tforrs2yMvE1pVDE742>a-skI9g0P-45mE zi4k|n;PC3&H9lkBzK2y!wHlGxKT0b*L6hH+C zIw_VrI}F+05+|H>L|<--OV8Fr+FRo3vklR$d{MK?TC_N4gThXTwazVQ^xzf|P*R-- zHDT3x5s4xn65eH{4>}IgT|~|Kb!JD70W~F8GvhAq%X3xHvSVWY`NkFA!+aE~gDbWG z-K`MaMML-((e8pr^tEgp%F(! z{&J907R)MPy3+wf&_#pwN7=>@eI@&LdW*&e@eOXT;A)EVE}Pb^d<5jzCh~ihX>|nV zU}(@3W*6F~#TzmAay|4tMtpO5f+FOwO8hX~8V!jNmc zh|<-`Xxag>(Laq*{6I10pD=WAzbO3!$o*oYYk(Xe##{qrjwoFNWRBSAIw1RtG1sS~ zaU&*Bb#Oz3%`aD$3)ls3Fz|6tc?6N z96EJgEVykSe9`2G{YsME9k-*a@%292yM{Iv*G}`ez z>)4&i92#?0^u1>vJh|L|B+mpP#ge-Nok+gaUzY4|Xg^k#oFPlzktwdZHwjJcmR0S3 zM-K5j#Sssj(4!sV!UxmP+k2wr!xm`gJu&=YI0}r+TKljThqi1J&pmQNDci(1j}p=R zJHS&_OnvN%+T9Ve9*3gmT}19l464^DYuJ-e4(;D8?tkip(l=+_e>#;zb30}Ac<#cP zz1tw?&tmb|)2isghOA95;yHA*gXm)Dhs;B>bcRsQZ0TB=D+{=)aci@F7cA#cXlT~5 zS0E#EwM@;XGIXo6UcO!h%jS@*S#K*KWWG0R`TOS_y0}!F{&6*`w^Xe8sV$m+Rvh`s z5gl40F8nmcyzmT&&~>xb79AHyU#=n6|7>bMX$isgge&GVZEQ8fQMz%?S`w0dP8h`2 zV#MbF6mv#g{JAE&+fqFExjx#_GOOToDA!raBbjwNM0YtQcd|oRy;G37p^6h>ij#)z zr$A`EZ*Y|xs^>k!6lY%9h1NSmKtexbm<#lfdS6HbNgoNPl>5tGf_`JvDvr! zsDWQr%(pPEbJNSRo-2RpIc=zaqO6{iW%QghSOC4Wp3_Xv7pQFC52MS?#IxV)ql{)* zU%z+YI&Zr0f9hG0`~TN74e0+v&%oTQr9TA@snf(Yzx>hs`Qp=GwNT7_(d>6uwBm@^ z?{^exc|<(=yB_-CBfkFq30=~QkN^0i4tmPzsu$Z9bwxc7iEE3ZP|-oLsHh$~&@{b1 z_X+8B*pcJ>kw!;Z4Ri1uj_Zo5AHYvIE(#spk6R+H9-88XV-c5bHZm1@Kq@$96}(+4 zc2RJ((5@U(4C`5V0-an@-ZV_k!6^#P5w&QHH!HYIRAn~q&T~%a%PbtnbIvGA!s~dh zvBiy9(87wes3zg3Jm|XF2wN(-%@)5hj92l!k4h(%+(r&HTZv;;97aQOB&8|WoYTZE zhf1Q=g@u!OtY|v!P>vgiwq#4E%5fo_X4TSCRF5P=b(C6|b3Hj^wgj)R07*Vsl9!rm z#+CP5T#7djw=c)p;6>%R-qp`ZHMD|GZt^CUe;h8a;fA8Xt$2!tYk~N! z_<)9km3|8rV5X85KAiuEO}kbaS;>#lR!@Tt)D5-%0pQMQ&9^tIb^5J+KAO#Du8sYiXbj%?uc5Bku+7gsH*5mHyqoTTWIxXCWO<# zP~Dl()N$b1cQdiZi|dG1%#`|hK?G?AkN}1%;YtFgX&1?+DYu5x?1dmK#?FesXS}%w zsM~bB$%m^^-TSHnh(T%El&|A6wffGmgQ?eNkp7Rzmmc|Wy`Tb*z%83|wiPyvpuKxU z*VSPTh7C*ckmlTy22*Vmuq5|!2R6@ zBt8Z#+0>>D03LlBU-IR?qnYicvwj>_qBmOHw>1}Fci=NALxnV1Pl75~#As7jIOh__ z{_{f0ZOvtH4%MGS!GUE`B{;%HfsWB3pWYMqTn@&GL0pqM70R2Mcz%V;@lNCS(hLhBTs*P>-Vn~t&AkF_pVL)Bs9tIRMg#qWMdf9K zE#O0SS3>oH&ZA_MvI4#u!a3B-s%Q$9Xmt;?n!ujUu!($k+*GpbauAw8N5>5ygYFND zf;+ajdRxvGrJ3O-Z8t) zU`T^rf&-3db=UM-Gs7C%=?g^RPQ#2Z)H!SQqfkg{FOYfJu<{{(+?I1itpl)mJFX`h zZi$Dq1LtThrFreRp8|S19P2u96VT5XtcU={t1;Lug0n%UJ~%jn8;qXb#F-JCliBiE zm5ClgN4kmcMsU8UODwL^nHz+xZsMfQ+=m9|{ow|RKEXdE`7JkomsVFfNFU4-gOhqg z9_oTkgY@kIu1rw9`{0Z&TmbqRjh}Xb`69kQ_V3DBBULYK=+0GlDR-SD)?DY!B~1~A%u9r@a!6{*MqBtk9OtSqvUH?(+#X_4n$HkyIsT0yKyn-Tnw?Y z6aLnXtAtYi!Rkovi$^m*V(L*7$S7*<4rVRczc;+?QEV;1)Y=PC#9C{t?atLf!+PPd z-NEFyeQ;iPt}>d?otZod)+5Cx4+EgI$?XO)lOyt&$^PGMPh<;};Q}2O2n#`d{rxN%@pi9nbB|y=ZX9=l>Xr1>K4} zXB>(Vk!&c;dyt`M6c(!cq_HO{N^)NSkA&(h-X=fN=zLFv>KnsKxzf$#mkN5P3`#l- zEdR%l+!OTaZfJ{6B|le;KMOp6h$}6+GS`&9RLV6R0Hs~?xF2&(!A0hp9^*~TahD!k z4f{KTU?TTCsZC8GHBV!y-2Y8&0{3xrcQlsj!{6|N9-M8>EWl|~;~X?rVcr_6Agy6- zU0UhFp$W{Mj|^+0@Wme7s|q*T(i%I;i2pJcpNryZph4fTA&S#iSKWa7g5>_61L>7s z&luqjjN$N0yr3sHz2cTDbc!pMeES8$Bl^NxCA}VA(3i8vF}=9D_6Pd^W%bg}C04Ke zjCc3qsyHtM99W$OR&NHYa|}r?rK~1O6C?54UR-u9Lz_}&6M||qZ=!KkzK4DX>f1PI zT-9H`;d8yYY6%8Ffxy{-dP7fxmH^{NhTRO_ZO$~<6g(Y?n zXPAOBNLdOuY^{ReEQR(y6)2(dIrEf3_a67}!|h0jy-KHh%4YN?Oi{TY$KdcxNlc&o z6*{j^CoG_TDuqCU#wyTxk~XJei@Oci1m?l4bJ(A9D2D)tXA$Wcgn}sG*ONcYHss1UJtWg(=4%-}>y2F+!ieQX6p{W}j7*9vWb2c>fuq)%~@D*Q) z=ISHIZ}@jKXB&CT1`&(HKT(TEF{Vxwq80}&p`+-kY!5gxm;mO3Q5`54lmn=aY}Ukn`E|t>#Ra=U2*ghZWSsYkiC>kRiKF1Shs?! zop2ZK|Fa!;`dhHgu`E2bx=@B57MVEySHYp36|12shr4PHWgq}BRhC8o> z)%^9Ec*;s{r`-Tkh;rRE5@`;GSsnz?rx8EEa$?E9ICvG;sPee}e~MtiV5!x2bBB!) ztsZVSMEA$@R&h3_ZGc9UV2^*xS!-gQ6SYaN6JfN#RdG)E>MAb1O67$lFvHx7@9`65 z?uIMtal&d&tZKG^+Hz3hqj7dUz?XXkL)PA)MsoJo7AjN3CIMZk7a8FyvkRcpB_ zjWz%-B(?SC0F70n00TCUNRVIPZ0tS-Y87VYut)w#9 zp9oxr#z5L{!h_wqe1i+)gYpm!G$I`qlkmWR;ryaMMP#KFO(qlQ|FX5%c|BKi!0qWo zFw8xGh1sRh&=>@heXJm|0dUJu3&22fdYvr)27?rGoDZ$Yc0%|o3wTn+BSm9kcr6mr zC9>lXN%y_jEzw>D{iow?>$$4cXH}P78`K8eTIWKETiq_;$LqOJ|10%i;D`^yupw(G z)I?oa8{$6vl+1xEoJqCOCY>Z>){ETBhkph2hLz+1cC+NFR6JeHI7>Vt{CZ_jb-Z)~ zH!)$F8-0u=nqolpp5IODy+0I}a&QXuldzDQ8A*pzn+iL6q_FQIg(%cH1{h6% zkycf}llG*9%I!(T1Z;VR-3-`@^fW=PSu=Ojnw3G!AZ6T=j1x^5-+wq#60P0Kllh0( zQx#6h^$E2nC`UFYZWnNAfJAB_l*K~ew4`8AK7a&mFszm@4vTx+qIX?7M|^7m4WS1u zN&A$1&<@fNg9-^`r8iKd`ZsVgLx7G$H*t0eA4y{?J*nw1i{zE?fhaZ^C?7HwEwwqt z8xDqhv*^r4yQ~ijH>{XVE$LD$U)=*vi#tkjWZ;xVC!|_fr4Y-tx~ninGe0Sp0SWvG)3H8= z&{7Y}6ZHZ&JbVjhpJ3@i{j`g!rL7E?00mtd9T-YR04HpgZSs z#}(s>b|^xi*~8|ziekbH5SU=1dNgAw1dv2A z;}0_hUz}yZG^#l+zYSJ?VKcGEHn>*em*TeDU|t(_ACK6^)l9gXT9WWk0Q|c|bkpi% zoikusqQj+AF10omnsCryUQZsF3UERP27IQw8l;1`P?je+l6$4RW(GLc1xPG#8ObO^ zx-*^PEVX@Trgp1E-Lb1~@u=*BQ<$hMp=I%qkPhwuyeu3%uHH$(QfcaE6inq7IpdMr zxhe^r??J^&I!QXzC(2msNVzjFUv^1h9$m&8p}Kn!;0Q}HZaQUrCD{=(oJ~lyxGGnu z!5JhW*1-vN23Z(FjKV@_luQSIBoK$pb)F3)Lj9yp2X->gCBm%t2>4{UT^fj5D$_Cm zzmlD|gPyC`$apeAw#zg0>koT2dSx}hk{VA}UZl^o29mX~;r&;#t1}mDtpVmk-4DM@ zy+C?HpWUJb|H5>*SNOf-S(ORf>L>*+N@ zf*;^uSkqu&*fm1^Tjat7W@E4@+|U3jhgKg1m>{}DbbuMj!7zJs5#+bBy8$b z$Lig{Sv~VkB5tWsz3ovbp$4L?(H#9nSixgAp}WAHRwxR=vbf880F z6n99dMQe|}Dh~@m&ws*n7Pk$JQgF|G+{|hRrqBiv(9SS(GFfTGTY8=g)%$sL#=rM* zqtNQbcw{!`iMGzc>$72hzLqz>n$7h_y^^tq#9c(1bX+9Cdh>!Fd**OwQPN%fJBO>% zZ>C_JwZdVy5<)K>)9XK1^$IxoyErZ(IIt3G0bOP|K!7d+oLn4jA-PU11{PAu$<$)0 zKD`)E+Rxokx8#fKVjz!u9N-)iJOBmr-V&HCq1KyH_3HW*nX;Kpp$!;I4u#b2jCPjM z8ZlZvqcvtU1A(mcg>W!=JZH(lQvGxx zjylZM8#W=mcyT!uPGRDEdHzB8IU06!V6^Z*pXGi8ufqkpTh-7&6ZuRiljJO@h=fM7{PeQR`}vL{6vy;?{d z=c?|;ICGe*sZ%YL)8|p+W#7)2hYuX%+@mWjAS%Lgp_L7sQl~P9+ETEzLn|`|;?Qc0 zNF3@wPmKd)?w*WuGh^w^ zSY+o$Gn(w&evBqNm*@ixM(37?_J+P8)Vp^Isdw%0wNqRV#mMg(oaV(1ceIBUPoSpt zF>+~kBBrP)Acst-qzX9@)UFum$Z5`%L)ow)cLweyHW)1VpXCO?qm%=sjpw*14hh5oqbMcBDE^pj>@g!?jR{0FJdWzO0HmESA*-{G(V zoq8~Dd)uH`0l@>x6K~%HAj!C|MP!oGpcdaz8hT?<`8aN00cq!hZ@u|2@6U9t)shYIAiQ-CiR6SOj9-$b> zp?yPfL1#spLh;93n$|^O*BT)gykd#M4OQ$aU09;X=a5flX~QywibL)Zc;|9O17s2* zJy@=Q8(C{QN`5O9W*kZn$Nt+C4*2qNMR_zZ90R#3b~vcW!ojN*X-McG<*z1uKf+4! zoewL;_jrwBFW)BgR}s$LtEeZPT&oB`=vIiN+MuxD&^aw0u}e`Kt>dm-Jw@g6Ghx)LY*Y&kjX2hvHjG(V0Z^s1{7NwguBXWVd1-dhRQI-%Z-(H)qsc%_Yzb z?hI)rrSDa|=1`P3PR>@up?ggwBq_W&w4q66my7>hj=iuk4LeDJ$UpH#Uga8p`k`DsFgPu?zjK zB0avYfG7RN*y7lmilIobmGW;YzH`XDGQO6t7>gELGtOs~FmNVGQ|~Amaj0QMoOxH_ zjlNWn3hpZYaOjIAF1W84gQq@Kypn<+DlmtN)Y8L8iYf>_Gsi!kD3VZLb0#X&jEM4* z20T-AB~M;Uhn_3uBD6@rZ4HVoiUQ>?oM6UR!I}bv6*{EEP6diSC`u_M7btR+iZw+) zr55iLzKHMl`)3ihe4wbm*o>csvVY-tGrk^5{e?3>D>@61y6(SzN|_%ObvT~?39Lo= z3RlY7^9N&X_=B)UDgOEX69eByob^SK$ZshG-p8L5tC3L1_-=nAe6$)Qf0LrVDI`vD z{>x7cW;jYszANkzKkE~-#RiZ12?=uVBWs!Y5jXs$h(=)_@q%B952(inJma_G8cKQ3 z=#lS<-!w=S8tvQwz@@f$;QQIPupD zX{RX<1{6JG{L#-Czvr`J1MWYSICH+E0=3;ObuQ0$;!u-^(q;{xjZpkODY^oGR8YHh zF^5T|^#E9!H0pxuSK()(e>X^bs}Sy+*Cf+w`~k#Qy$T+ScHl!KjU7M4qUPr|v{6rJ z^qrozi-kqsABLRzWU=%5L1-H309mYHlC z*N7KTOg5h24R#gm`w1m$Z(iOkYQUX+nD^mlT6Lo6LwR`;MYrCEm-~RZhxQU~=mkUX z*o!@y@u|pZFFw?auZezV;m6JRO6X-4{??2igT`jzVa@q_D1DC<;>%y<(D7ZkdJ8@d zwcdr7x8Us?JM98_o{P>>ufX$x#|*Zb?6a_JDrY2sUqW=pfZ)yu?=$h+7QBtstxUOP zCNWTbHWOEF$u~vwGjWHOygeF`iAS~MZCZCRvO)Jkr~-JloG9=$5}-X(053EULQNw9 zQ^A!o@%ff~5W2JzTlw=YX#Gyy%%87jKWiuGKlT=06$9&wWw>WJG0ZdF@i=8;bpRbQBcjC+bd`EP6hvXQ*!{a{oaZ*Aneguc!ZI#}&=1+6TWeb*q z_yntso6E!q-b`YoGVT@3k3^Q6NuaDpLpR}ZZTQ($9&P+t1h3|u293waAi?<=xKKK` z5nF5dl!oOd($ML$L^Jn_962rjwJ469if~>WIhFsl!0$cyhPY76JE129xOxcR039!o zLgA=HPNSu1?fHuev}grx+X=>U>m;2o;3Rbd6b*on_Vy_QQ!5j@Ng%`jfyjX#X0F2?;M`Ddu-ARN-2Z=e}}yTocg z?QLmhcfKEoK8w=7J^0!RbTJKA=*{;I4~jpMhdM2YL7X1#{k|JeM-fzi0pq-vBf~%wpvcAESq}m z478U6bag6jIS?{nrjdbY(5ok=;=u!XA75XBHdYi8ceFjpAUX1@8QamQC4%MQK&kj1 zXs&OV{oh{6wqG)mnC(YqV~0VI6zQ{Z$RIu#h0Vqb2El+fHnPEhlE;3b?^?Z=-E5pY zh<}89XW_Mjc{ikbIGK|3}f{=kc^#&K|N}ij5CMvRZyj5e0~`3i5^bJMFc)M9aoLz z{c5I6haSRW+8ahhlYJZnjwKk~qVueK8Gsp1F5~>sQ zUtI}-n}x-r_;YHBMkZM9$`d1jYAlt_=Zpl}H_~}|RCXB&%!D-n;+A9iCTQ?fJaH^< zUoF_kKt&QGdo$7`H9Zj~8BKN` z(e4dO$TAYBLgFpiDa(um=n{(rxkE{laj)^bwp>%f zpjWz64VBa+!Q>IpOvYEnLubBDl9f`~#BH+d`;#y?fww^?C*i6S__}DxBpf^e=8N%@ zh_#h)+yvgdNoQkgFxl8E*=Qdl2?VpCkOezT!bgZ;)g*jt0w3akXd+lZqKMQoxwsf* z$;K`vEQBPhaR4)AHSrU1^hCa9-R?#f>I&i`*%kgq0*oyTs>ejUVfKv*Ok3xy|6VKW<64Is~-tRVDWD<swvsi0SL8Nn!Yn?5Llp-}7iRPA5IWsoveofxIER}3eipUW9lFit{2G-2 z4AZT+OF*zl*$>~I%jckWeX*$L2cf6Y(oa3FnuM0^$Go7dSuVYv1@Uo%`q*7ic0~1d z;bcMi1vSo;rl^!P6-cvPT5YD>i(G~{Q%18|7A6L3CwS;2-naa}kIZNltE6o<6 zbJe9AYn9GQRMQ6k+@!3D{#2G6HY@8pqqI*_`-{q39Gdt+a=EO0z#;rjQspW8TcI&( zDfY2)m;x!yq}$Jwc@>f8S7}?JGFX9LeUv`^RKh#RcRxsq-^z}SQGS}#)kC;%n($p$ zj@&}C3edv!&o2NpRw0paRm9CDrvb3RsIJVgu)(OTMo*L2j;*=|g;Lp$t88(?u|kf?3N(3MzJIDm;~VtN*jUOCkkDW_Xs@lq+pF4 zN8rPWLW^>bhkqwU@Xl~NZ?jMx9U9I=H%k)Qqt3(eoFw5F>Kcn@PZ#WwS1jH#U1*Go zhDi^n3lUt6twX<)x0GnH&I{0;Xr((eEAa(c5i92pl{(B2;G(wk5IiSEa6}$M@QxIr zsZ(Lh_o86kj6}j0=s6=T_cmO4(1LCY(R~M~_})sP8g`s1R7GoIu-{DRTtW=)GgGLK zI>uoAOz@^62H%}2tV6vAwF=O8-nxF1y{TxO_+qv_QI~|5I*`|xZ?t08q)N_R~87%(U_h%cA?;J;okFm zQ6PD`$*XoxDQBSoyPcsu@WMsHB9z^oHJ#cW_fHpMk-9s+nhyAhk$CW8p%bbZi4QIo zdZ07iuniW{kXJX{aV-qIT{oPI1y5Aa6@S4(ryA*9OFBw=7U(&bjtLCLl&<*CT8R9a zO9WfgqASi=0_|P8VrhxsZuzAP1P&W{h@Y2T@RD^x4P0rdFbwtTf|HgCl`Pu;i*Au~ zBBUPlz^4n|uv7>`|8~ZomkRDEr!%g-Oz=P{opJYNLM}QH!6I{e1c^*1+<7^K+>i(s zm+c~0Ty9$~SlT#7fLCA=381SHSSaLy1r`zb&1S(7e_AfYR~gocbZW00WP6Pr>f8y> zSs^sFuLk5+y6uT1_B^+zkx*o^NC^Jvh###GJgv`lBtuBcrBK!GLO2U-B9sI+kqYAW0vd#4$Jvmv4L1rZ+CwjQ-Pj=&c0f`n}2(}DnqDV#R-VPy7jX5^+xUH?eVn?p&7aohBa%1 z4CEGucdvo$vp)AxUgyNXBFw%jcc-dN^9s1Ue;UBdl zan%g1Z^uGP5BPOLQ_IfnN{3W%I}%dMY`3;0gT-9pS?rNTZE@T6LX+w}feH@}bS9%j zhqKrzt=i%hz){1DaKPhse;1ulz1O=C{BFIl6SWM%t2aQ0YKE}!d)A(E!G z!TmM~O{@cf`qwCXw81+z39}tG1v8t=nnD+RARsjuci9Z%6CTWxs!=dWDo3OV##c!3 z{}4n{Xt90wAR?t~5YmeD}OJ+t?OT1toRJjeALS^LGk|l;&OQN7UexE65(ES#e+a)Zt4{1RR zV%-YReF)UuCz&tzu6_%=CL0`ZZkJG#dygMw3pLO`ez=I>YVL-RUhRil?iQ+`8Gg9O zZg4{fKRkc85Qp-7arr$kv+nf8?t1_~*_YYX&lk7M5$y1?JQkUf}iEN zW~H5Tuo=m0M;y3UxQ`C{;F|jc$8t-2V4PD2I9I|gGeO4yA7)RO5Al;Xs^~*Zslvl{ zxHmTJ1CO5f#+9;#!Kkk{j>`sJe%{0tEzs|#_;EG_=EJ7M4Yh1?nv#S)5poRPHwjt>`91rVd^6 zVxxJ;i+IEVx7rULN%msl66-~#Pba)+zu;i$>Q%aZRWIq}e&H+JLh{6i4nhxjPkiT~ zP!m0DBo!SLeBpkk2lhKGH0K9+z)&P@5-Q=e!$K=$=7Fyt7J8!X?rd60cPC}c5nsxM z9zGZYQ%;RTf(zbtM0j7`w;@wW=1<*e-14x{5Z^xv%iT2%$O5qio(hdnNCRpCU#|gM zj@c4f)vP|dkx)ED3oT5C&)x9%Tv!yX0yHT|#;F5HIyW3~Oqh>;)R&$e6H*ZxS(nW} zk#&vp4_G*xYM zp(BgK=fHX~@{I79UsoIKwHhZ>#NlU!S7=Qw$?u%-kVCmOvE2nB0u8GvjlCdPnjxQZ zQpydXrGN?%K7CjC2VLi+W%q;y92)%?yFCyB6gP`ZrO^+B&qyKtGL>Q;3tc(Ko#AFC z@`cvOT73Z+6sQ@g)XFF7KH>P`6T!B|bAkxajQE)HRWqYJy=+r=EP|K)^ww=TsnSzH z$(3vUg~GnyB&TP>fle1gGUZfsjDQC9Do7Z zgUhs7hw-0YAb1qUBf5d$ju^Z5P}RdZ-BebnBE}cGsj8ZOTUQTXh1KQuel9j9Wy3Sj)xuGU5G@j?!@+Oj*u|-Qud6Q4xg#M7iL}iSm zqMoGSUok3ov?~QS7y_E+%jEZ&l$@A?dk=vg^-aNXLsV7j2g_s=5Np&Z3$9mIaP<^? ze2A)n)$19BMeTJna*641W9R-1%neo9Se*nk=~2dDs%PH}TxY1NMw`V(wA>@hk{(T! zNk-LVTTE6RZEVH*)NuyZ4~0J2&%j5As_fC9Wc+BT>So>A@bYRYQ)~bvCXlYO9Y}c- z?ay@lXqf5~xBNAz#7zeITB2E~gI%Bmsfmkv(m#Bu^ot1#Qja1FC`WesA#3_J&9gjZ} zbhM0SE>w1m$NEu#J{8BfWps8Nb{(zKTe*})+s5J31f4pq4EL02c)%D{s`b06q%ZF* zi8ZpIds8tQtJ0wkQ}O(B=M( z+{2GZ!ha^K=Ad60c+M16A{vt@Sxi-ZN2qNaR>iBDCbWnn4}^Z#)fm4LPL4fNY89v9 zOLCd&S^%fcbtaEC>$E%|Y#G9VA_#{$L4-QTClwnKiOlL-IC+PD?Dc+Zleg)sVe{`P-k6_9+U&%pgq=yIi9Ni zxg6-4Ow&N!Bp!}_F9C*LS~61}GpIf@;Q#`wGl35o8!5{Q0C$zsiww?#a^vT$V97lV@o|)<& zw9*@U%vXgf?A^`SQ<<7jVm5m!bL?tZ=9PUaGkUdDK25dPrQaPDxP!iook5@3RTjXP zdpyazMDOV*eBfQ8Qm?GMCb++z$~FM5)Kl422usOR*;SWd=Nwhd^81#-t9IZOu_-aF(rjvJ6a* zW)B?G2fkI#r~!`?55NpkgU4$QsB8i%0T(>2OdjEd7l#YM@gPG(ktz8Uxj}wO#f)(p zDDp78i$OS*JpO(F)(agK*zcg~F)GhvheN9Q^k@lSZ!zp=EL*WyI3!FP-IFzg_N0$#lUF08Lg1f zvKY;jK0K`6R~uJ3qN=C11+1*6Ms3{jh|1pIf-#oWqhhj%o>K3{ag3GdgFfX#7mI3{ ziXWO)wEkX;8cVbRB@ZayfKsLT0PK5IHKE_XMUWmeLQUX9o8YwXX>x>`EPzlWZ@ZO> z&|g6OJ353`=76`a)@0E{WMrzo__J7PFmyVci9Y*%rU>?h7jW9&SK| zC$MdSO1!O2rSIm0C}&F0y8;1%n7rTzLhTv1H$`rUX5&|tacU{@a17(L{)OvaR5dSW zX!o1ku;}{}kGQC^$Dt=w#}#(JRM_gIYM%N&_(mS%Cuw;5NmaGxH>memMBk?8ETRdk z9MMncDUIlt3`-*Vbs9#eRP|lnYG_1%BZrcRE~H>_M8nhMT~4W*s`KEZ#Cc zzxC^1DYqX!h(sraT>51sW6H5ab5$MyELa{cCx!#4lK=(kj5%k3?=Y3hxq_Lv%Q?uo z8Swcfc@$E~mze%{&cy?%RL&((kmej|FXtR-FX!Amh9x;Crb>6uk({&oR66G>equTI z`yM53A3G|%h7h#q2Yc@Tl`K4!Al3xpF;hvXO^&2e`ibHuRoPrZ+WhqHD5wNoVpd_i` zx#|PZPCWrWnj|}asx?cs7(o3e)%sJUG1Ue#7Lo`cYcQk9sWybsNbmz~m^JQy1yb#D zrD8qTDzQ{M4yga=Ib4aQn#72uQf(i_{GDoA2%oa;EHF{3dyQn- z@d7G7mrm5`lLh$Bb(q<97A(F2i?Njj*zpD|#ufn+8GK+WnaAc+WQsRM8t1V&j8jXI z#(6BI08hRFId#>558r^r*t`OqaZ@#49R|LTd)X--``&`7D~P&>rB(<%XQ@S4<<#m# zPibm(V_1?}J>&7hTd)}G{Tmn|%E_T5pJFIjJarBEt->#EshU*shfj9N76g&6cM(71 zj8m$r9U1}npLlnpNMl|#WGr%Cc`%xsSDuU}=arWQUYZYiwFJI;Dyv&*j<4p!6gC%7 z|IsrGh-3;&V#HE;l|V6n=hbA!S1PY2nzJeF&~2E)3dd8Qa1-G0_Z0REXw;;VDU5}} zr}5bQ4oqRQjSQ}8{dnB*4oqRmL|$=%rBKM2U@tMH$q80KpfU+Y>17h^ImY|%sQTJe zc*QI^ld>IFL9hZM??tL#VUN2imxRyoxm<9QDNtZ^1q#vP4>@ScAX3}`s>(RYnhQ98 zu^^3PwDzy56jJel=1!rMNsQKs(P9{_F{3RZkd=NmzI9i10sVM_*WXhm)b7}&oXIQl z7FZ~p7^cFl0BzBUqSHlJl8cHGG6QGV)9U@wt#HVF)vyFhh&-+0O3`C5?bjHRYkGI) z;6DJtr{-W1%K=1K|1-ex18|`4EKQ#s@X<(O=NF1h$!ADgg0xgR01|R>7m)>D;2;M} zbv4FW$dIPMi9H{vs(FqecvtmAMkeZ@DU+@oLy<<6RJyBr_!yk@Kvgke$!KbiEPfe< zQc8(0$gm(LD*eZ?o-u=40VMYf5Ugh{07rTT2x2y4^r6Uc5O)0Co**M(zp{icO%CWS68_5CO$;2@o$~6>eRLpd!S1?YZ7&NY8EJPzH z%wRNG;aWzM6|QGATcRH7Ash;(n43rs9;(i93D56QC#0EEF)smPPRIuYbHY==k#FY0Sc!b-oP2TKo3*fI(xMrQtf?QP$(jZ*nyhIMqsf|L7%hfKvC>b1L%|Ue z!vNNXjnI=0gen7Aiys9Vr1eweCxT&C&7XcVHr+&Qb?m> z9;IcOhODrw%^9aRJLE7ph7?}g9_;XU#_Gyg-ZK_&3MoG_nwHT%!<2USg{p3BH-dImM>AfcwOEHT ziZ!8{Q)M0Mu8fl?28Tv67FlBtMw2!6WHebL%(Qs)OVx|o;|G%-hrI`_Q{a?zw+?&= z!c{p9AWa?k9)znpX)um6sN52q2+CDmk5VX;dkK>l!#Y44_t4bgh4ANJFqwIRU2MQZ zxX@akDmyi31@q`!K)~u?duVE`b0{z{IOq_8I|Jb&Iq3;MxK4p8L~{UA1{xAW;q!&} za8iNFIbjnZ!BZyiU%kPI+LD8-de2=VIK`Dh%DoKIGUzmg^xlkfGo!^Y+K>CBoj#J$ z?olXZHlzJvv`LKih|xA<=YLh{4L{wc!IR5qUjU-sO!23sLirgGF!6@7!twPsHvFsd zsx_ZrUDZn{(a5^24C{*9xYaAwPXGIFRVKF~f{Wg(Oiq4OnIwHune6_cGMV#PWwPvx z%H$yYj|BFp}hT2naqd3VLw$SH{lN_-cvbMZF|kQ3ZAV7H(4sH1jECq z*-EEi9Q#_8jNWkg!)w*}ghj9j3Q=69b6?y3v}f|%7Ya~_?w{hh?*v4P7I5G*GWTgy z_sMf#Yl@_EA0TZ>g|<|VARnqs-B)(*8v;m>S88&?&)=x3B^)AnSM@1ICUal0bY(6@ z8dXy1uIht~GoNu%C6>w;eW`KsL};K;X(S@4MBFpj4^Q+W&iIHqn0n zzr0?Xnfbgw^O^IR&&)iZXC_(@g@OdpsUV{yr&B>TlPpdJ`H{q&3Nl7wP>@GoKtbA0 z5fr4K?ez<{nyh+Xv?Q|R)RO%Xl3C(fOg2~V{uJ{kv}B@ebEod=AwtDkvX{i1x~q@G zoVu%Df13LzwB){iq6v<0r>s0YGjo?yOCA(NoT4oToovbCOzE)1A|!THV$PI~Nz9p2 zp2UW7PN$aSS5%@}F+cgYmb`bjxR^ddDe;=W1sY;;Es08YYRRj2X~HXL$&nnypD{h0qmOcbNFVT9z2kkbCGCErLb*#iU72QAqPAzANSU&(q;1PvMDx~dIQn<&*> zXF(NO5=5t#Y$sWrI;(?Zaq6s25_9UTF3)K4Yq#JLwx^;%+1$aHA+sry(ElumBH@xG z47(+#k5rO-B#Se_eG+pfxL;z<1P?wX&%fM$t8uwIFR##%H{j)kl{)ekLQWldzdM=V zKu3PbNkImyK!lE*|AA?dqzWBr$xL~JUv$9)QS17GNjwp$BcH-As+8+U-oQ^l;5yO* z!%(gxWjJm>4+|a1J-zUcPQ1YzY~RydM;_rKJPlP&a~)YJHFMV4=CNZb7#FiLuX{WMmE<(l1vY*7HvUD}HI79o3+?LntnlHMK zQ%`nBNYrSt^6Lh|2R)gXPcz;^Prf(-YLMYAcWM>0{w+eqD)s#dy7$&?Vf?)JZZ1{_ zbfb&nG60vE`MD}C19gf^5Z*O4(JL-Ju|MbMrntl@ic5K1II;%6x;R5z#X>w8KYsL> z_~XZ*R!E&zgwsQ(KbZ!FigVWX9Vu3yW90C9qKk7A=^Q-&yNPs))Ba}@DGxL(tBbd4 zi#qexC^=T?ErMdlr)*or9`f^B2X+42t^B}6-AZ;_mcfg?j!>Tb|LiHv1B7nE&xwpc zWz82sv8Tl21F?h3ef_k4>e2 z4pGi~Y%2YEhzrT$dKU98=NR_8AZBnqi_?LfFGn6rPOjQRVA+a!YBG@XIYF&WZBOLe6&xuh>$uN$Pi? z?(aekbV{9?2QPv#$Z(uHAGVb8M6hH_>BL3K&?$|}uX#|C{?W!fV*godC` zLsjHS^)*z6>@qZ2gtD$l&R!BzAQ8jv4~K;msrC%>MJOXkVml<}BSMCS60`77*{lef zpjSp3P8=+$iZci4xn40Dj)Me^!CULpL0h@fiodSX@IA#t%21s6hygk>Sj@;<1XF^W zlEw_b(Rnu|CG}{n4>R)N7T!Ix`pMKsA|&*Mc=n{q7z!G)!k;?~_8r7vWf&-k845xm zS~$^DKlfwE%G`BN=3PvrJq?*4qRN8AD3cWdhjJCgH}w{$;{ld1f7DB)>+cC-agsuM zkm07}bS5bh@zj@=oX)fq$?~tX3Kq#3`4923m^>G-Scor~k=sF$<@_EjyqqBLLP*Yy zf|#N3F*|eDP&jDKb&^v|Z!zFWmLQ33keG7<{hh>6SzL4?9Q&epIU~QLDqg8&I38pu zFWGorN|M$ar6gy5WYPvraw;-0cgf<+h=;_S8S#{uGb80B_OFZ-jK++7jHdjoOYOfy zRL&T=l{63`*$4K3AnT?tXedA)2*}`e$=E{>GpS(^YcXB};e7@gkpqc4q04fRr-Xr$Y5^rKPnvRvaq znIfXx5TW9vZb{6U)E$XAle#A{XHpO1$lX)%iF|WZlrUOm;4MP3gn1yy621lv>0JW> zCCrwLFOE`gPbD&J1_y%-^8`-@k5s~=pZ%YRikv!U9HkSUieF?h6c?WRP)Qw+kh5k% zkm-&Us!iD5KxTv-)<#{Vs$~_gIzuIBm(hodP{tb((vOswB4d1dk@}TYf>Y055IMcU z9qi76wM44^vLF^GwOtB5CpoW4p%)~JGr>y|b0&C2V$KAwNz8{QkEINpg3GQhq?J=H z*89DwDD@gX#s?W*AjC^u@~ZJU2p{yzA5F>KOKDm&ol~*jBtY@*AN_pZe^?hFL}k5{ z%HahaL<8xs_u(mtss0^!MdijN$eO(k0_Gf;W~clO!FT#lwwID*^xE;S$+q_n3M#Jz zr0PIKMcv~wZVXOxOUV64QHhG&5Au+qAQ|!(p)4P{yk-)!NUY0GJYH6W#2SfE#!!hR zN-R-gO(Zsp^2;mZ>y6wdt4(5`A|$KLUq08PKtQ#H%4dG`HX3bG!UGjf4KkD!V1|>` z>p!ffZFIt<{8qNI8Hx*sTtaKXiq7!VmvX$7UvPaoZLFZAm(SV6>mVf?X+#UfW;nEo zKJrlp$B(Y4xQwWzxGeC+YdhSGt%nsy%gTz2ho9o&kIOP*s)ANcaS0AkT;Afhy}IJk z2xd!VYbY+g@hhI7i;D^>cuxCE&d^nKPOE;;m=E+QBTB_{3W z^iL(G$aud?%$8nB!DM~tx(`VQ8HTT;hLx4-tjjv;QCacp(GnNW_ z-b4Ud*8uR@yBwRsB{$b*eD*FmLnSBIW_h}TSs~ZG;5c%g_^tGQ-)36RBsWUqpkJ52JrE2?ya&Qe2 zt09rCvE|D?b za}48|Bsvo;62uIipyjyeF=7sm>u4l5Pa7h#o!vol^DKay_f;qN1Ig{lvjcW%C1JRI zgkJb7dm0DSEh&8vyv0?AQ4>80I%JJhrIms4!BcjxDs|~zRV6a@r;w7!d*J=w$o!;f zOpk$lh`L>bGR{e{mQ@KBJUkF$%5kiMU@UrTI&vqMX4kh3RCZ1H*_Q$fE* zL6#sSI*Od|I!jB#0~CXK5wPN!HeM|tLgvau5zR1sJuM7SrW%&5DXFa0YsjxU=J`uN z!aV;Tvbb`MEvC9+)Ok$tP(>L|N{n|}o}XH+Kc zH8aNMWa{f8?7TYzBW7ANGr}&(hU5COUy&h1nNc<=mwjMJYxczg+xiftVs&!=t|S}l zN#bKp3@MjMPllt8ch9245g19Q&7!Fzls+tU7TpHl0*BW0J-{I9uv)vt|lsgT$D?w`;Lz3y$`W?vV_V(?-Vt0U zQ{f~flI@v9H6|;ISj;3|6RnIYUcZ&(?a4$c_c!mA^iW=>UVv0f>*9aEKDSC5R(KGaF(XSR$lm7_Y(pGFIj&N|sO z+Ln~A>}3J@pRf<^=- zIAL9XOa#gr&cHpUUy?}8XDfl_CJp+_kuu3LQ2#wVFi;sbh*D-Ni^?DF4zX!R{d*pX z?rceW;y>IbCiai|AD!V!}JlT7OTOZ$H+L5T-sr}+#i&*qe0HfL3MysiZ zY1z1}ME^|WTmLa9XX^JLADlB9{{29X>%Rhp3qG!&10U~6$MuVyKKU8Qh-_Z|xn1db zmf{_-xIPz@P|Cj;)S*O^iiu!c`3cpUtHh?xgAn^z-XKUX2Vp;AeAfch;}d?sup;=@|eEeEfE?2=pWCNIYw4M?GWu^zFlEGhx}0`acIDrA66C z(gM+c<}6m)v1N&LYq8?PW+l?=#mYyleIhj`r4tKIBr7R?hR5A`|HA7vhv{l}vJv{@ z_L}sJl*)B3aL5|xW66xeEx7v;!a0ofx&J%q$Bi&DJij|NT7ubeNKKhNi{-C#c<{V= z5N*^OC%qXuc0j-p*a=ZjokBPU;Q~t#e|q$B@E^et9%L`G3PXIFQp*0w!5=w=IUl<$ z{n`PX2XkPhJ0I*VS>})M*up3=0#0E$i`CVlU|_|_=aWRQmnZ=hy(I2lf=l>TA~jg5 zgs_ZWyi-+S`rbI@2%0;(7j0OIxy`;_bZV($R=vjH6WJ`&6NUZ&tSe34%anjJX@ROs zN)@D@-;QFJDIM8_c0|jR8Xk`7XvR0XNgQk0j!rI9;@ID9soZjG-tGyu~^Z~ zx%#qq;caWE#mSk5PH>{r9m%)>8CQv)L>?7~DYpy7uT=U}84Ol_bq%sw-eTot5Lu14 z<~dC9T_|@Yb~gLWCc`QueISV~lIX-LC7{}&HewIrdWsiXzB>wf zO#eMdI(s2@fRMcYfGqI#?G;2-HkZB{FlJ(_{Zjys3Y6#_%sP|9j0((6;u z-n%Q)nkp`-?f5l*EB8>&YQ@azcA|T$l?sujPN>{{o=AnGGk@c;kA~v*B=odQ)Jde0 z>;pxCS&OMhUsOZX;glzUe&}WkU87udP3_nQT@)krzBNW{wr#_cho=i&w<@O>yK>5b z(s*^`iZlcmzdSI@#Pu_7A#|9kaZ;GRjW4P=%akt2xbsP$54$3V2`3VAG(@7GmY_RZ zrE>UDYXKW2+^+;)B_iiZ^hG5hx>E@{OQ4%2dQqZXO3<+aog>j*5^Yz4_7do)tywD1 z7fCp}1a2kZ4l?p2i8d)gLj~GEqCF+rumr6n(DD*(CegYjXeoidju!>?tE3|REK^Vk z{49>w$2AG-WaQc<=rw`vljy^WqCTpZpoayzLZZ16tx|%1FVLwH-6&C?0lfVDZZ7>| z0r!(|ri9CtM4l$l77`sH(efqeaDi5rXj_STm!Mq)T3Vv@N)mRao7!B!c8jQxvj3ZK zkU;Y#`qD>~SZF?x>2d=7UZR&J`kw1If&LxK>vFC{Z4!kkfD?Tr&@rhJUMgW$0-qCb zCy9P8(WdQ+BkvPvLy7j5=%bQ^*9+8Jq8~{#x+Lygfxh`z6u4@tGvN|=qJVEm*j1wI zOGFP4=zfX*T0zvusuDCopsOT$T%t=#&_)8CCeck2U6#t>Onm?_)SAOIK*ClDFD!|y ziO8`M9VOAlCFq|mc~#etXnTpyFG24JRFPF-4LBo7PPNq&-sOUSz&)l?yie2#n3lO;%1eLV46(wy_V%S&$6WSsjpx+wlD`(u5cEt$F|DqN|i_;Q8lQ zgs;JSmjvq~1Bl zf?20AZ2&5~aE)pC5-u?q> zK=wGN{>CPOVc0*4OInd5IgB6B>tU}_iJvRc1w^RvunYEX2m`_7Cre*9n4TY2;wrxW zTXAuu@DJ)(qF9DxXsHKrnDVNx=u zKhiksFjcQZH;yRPYSt6-O5y1Vc96_EoNcF8|^E#uvEyWyF$aqmnX8o&)WmkyHeN3UU^kqk)(*Lgo z6tq@6eD}P0WX6iST=XH=33IF$Q_QlHf=Pup)`$$I4% z%DbTq^Bid6ok#58w0D^B1!l}m#j9B;c2w-$abXHdT#H}voMj3Di7!cGB-INOJ+Vf0 zn7pKjLKb!tXG*s9q6IgVT1_q>S>7?aTGDb$#Ya6cX4J)eG{I^*@eoaVllP3)@!~#d zhiQfv=gm%TkYLqsen=g5s8!1QyOeV&3<3Xi@E7iZXW~PuaZ72P+H?@cOI&HF4~7Rh zOQ?;^y7KutL>PIu=0h@u%yB$pPX8xJ0t2k9KX zLk48I7e}uBFF}n`g`|H8I=}_-buI*Ll7cSOf}qd-e?bp;r8skRr<_>PeOQ@UZy;9_ zA;5}DAWf?wLYx`|sXaloR};(si`H^ydETH;7DHGe#>Z9VXxeQh&{UI0g$%tn&x8c56R(!R_PS(+7>F#aC?B!Axy*W!?l{-d+3&8IP-y_)MNnP(K1Jt&>(Xvc)zozUv%1d_LNW1RhP4!MAmLBtPV@lWwblV?z zs0blTq)}}PJLRQqcFu{Ewp5X*Sx2ocEc4o z@mcLcix(O8VBEcm+*`P?ERza-N!{-$Ls;rvI&@E|*6Sy{BEhAaW$YJj3&w9`*wvDj z6Y4N^_230Vq0-*@q@0JYOb2W~dj_m&ffL||%eP6PmUBYUpA6tH_NyM$?7p&w9lCA1 zdmo$b?Bz{@r>gDLLuC{0qq!kNOMX=%-P||3Lsp6h-Zm9nq1#WCnJnUhZOBsv7vCx8 zZHu2N!LICNqV32FMPtmbyY1{tr7UCLcOg*b**<%%OxLkxoos*ph0%u9?qD1AR#|Ce z%Xg99pw_U}($pJ_E!|;5DA1KPh@!2YY5=wORC}=>o7fN-sriP5qO8WavzE*@7JHus z&}S8}s|qbsJCqvwswwQ7dbGt?^=Av}(P>|GqSj0Qv5e*is-4*EK>8(69mnF9Qc?}om#qn;@io*cm6K~CMe9{QY$xT3cSsq* zcol{IIX95D*HD|Xb0_Fo4b|U(YXtfJoG+kvHORN7I2viY(^kW3_@K51=5uuwFA3Soq}qqVQg)6 z>Rn51UAcGl5(%wxrR-(cPlD`ks?m{JYPZV22b6GJIx0B|@W6v3rW%FUR{OAF0ko*L zT7$I>paZp4pUTIpmc;OJ#<-4Y8)8%ppcmj^VURbvvv>LGT{h zf^~P%KNH4cU5tkh)U-D&Wl$_EvT-x1zP*`7*HsgkdYBH>Rd?&-E90FTt(mFwrn&Xh zd2DrQ@(Wd4u%4x9V5r)W+2_*kP&J7SK1gNjtKO{ZL8?_>jbzmh(xCck;|diI>hP#? zJ^A|qWB^-Q7KiE90oqYtjnV&jK!NbkJ*qc(G*Bbhu|wp)Ppx3WXxttPaW6&|X3#fd!Ppipa zgP4;l+Wu*%=IGdg!<5}ft;6OWre}@RZdHP;_@vraJ~8bR1{ zN?|LcdS--u{O8DPmN{)4jcBJfV4cU&>UL@sR&U(KL+wQ zjAb+;Yk2TJ8f`nauVbqy-ugV&`iH}mwwMBX zs6AP?#WbyliVNu$Qn{XLYc_2W_35cLXD)+iRZlg@yT&5^C?&_@`sr&JfU~;V9VTs& z?N(2f>6-rVw`dakoeQGwaPqZjiy)n`pOmCpAbsZ~?U5vJkiPv}XRFj(jnH{$%N3U| zuxFo-p7?&TtzRD%*URP3qXm7{A>{@y?jTh#L@jc^H1*F~iELy;STo|YY*sSjRC zVg1y4?CnD8&|j^S#wBB^0wL|*;XDCXge za65~J^@o6?U(>SwsO@<~XZoux%GSx!xxD^3LdSR7Fg*;+qN)SbIUd^bAYFh@LM|)gaK(hy`{XEq^iVI7wy_a`FhiRvk-VRjTcy#ZH zY2``2E(tS_vr^|lYKIDC(YLS*SWY@#(kXAHeS_37Y``n3Gg$3!Zaf?9T@m}OHMj?x zXU#&m2VaagbDvF{2de?>Y!aOvtj;ML`6t>Z=U%CJ*El>nh6aDq$RR3@r%s}IL)7+O zb*(zQm^fGHVLcg-qj{|+vz1;9QCqQL`poK z)4#g%$2~hH?cPUwqrnyvoELV%auII|&mpT-Id@ckvbQBHCk89Hi+N&t$lsjRoyA8L z!$&hwX!o=tU5Wvrc!ccS&~!d_PSYY9x$q56(|*ai2#)<6EWAM4D@mI<=>R8LTPkT0 zE-Bu}^t&=BVz?T|eoLp+;p)-KN$H|@TQ53H-Qb1Vft?y0hiP>N^&O%5wyFI)AL<;Y zCK=)(@w4C_mk1=n=?>GSG{omKD<0*O8C)2LfwD_eixJtNO!q*qZGrg@GP+U_7O^Uve?wpNg(wo?xZXpQ;O#qv!yc`rWfh8Lf6Q z4nT;{mA=5cLR0VAG;Flmhz*`jYe%aM)sG<&)2N{7wmYNMX}G5$mHK_AHfFu2($de= zXy!YWZhoe=XMaqkI%CyJHP1}NHz#_#t>nd9@s`5308qM=8kR`?+Nm^ZtZHsNnbYL! zIlhmOWf%s6eG1<;&N2+<{yE%_l^*veaG6#^R~)P|Rz1opB+$%p>Q*+i4K+$u!&&_{ zG%8uG9#f_bI$u5>l;E7%7{1&r7tdJ2{@@$nnf0xw(Q6;K2E$?WqhJZ2wS-}Z1WVG% z*dsTcYE2iC)rqWAYf4B_2dTZL;9_~J{?~Zgn}RA{6i@1SXtTqUY0!AJFTR)6Vx85CsDVUV?HM20hgWx&`9*s;Q75qsyxSOUnQ30b=~hD$9Q!FwLOsBbWlW|ymJ@A~IG^)nnj<-B zy(DEw(s)i<0Md3H7{(w}-r1k9y>9CG5d8%A%|D>ziE3j%`*=K#XvUPo4hQ&o6M^a7 z1Hn}40p(9rd$V6BQmsi)^lK;5s7WebUreB-lT1&J#$o}^n zmAh5HTwjt@#pWibxQ+rmMQDQ(xeAx^z!XYSIp8EV+Didez$=~74F za19lOn{?w3V^ThThmq=I(C__WOf;JXmT34@78pZ7 z@EZ%v38H!KA3sA?&BPK`l;sHzefbC-;Sb}Z-x9J+H!%ZF$TDB5!f-j~qfES4U>P28m_LI3;xUJeGTj0xwJx5sn<7d<+klhCjE#J4 zWi^~DAz>%Rs;|mp^M@CYXa@YobU!4Gz!(vzCL@(WKt8X!>x4VA!q}AS)XAy_w(6?N zzP}P>MME0~3-{lBU-tV^f}Usym-sz2tn>LuG{@Ya16IuLUtFi#+&zDt{;{f+$__@V zXmvaXNsrL~cY9LM9JE}O>(pV6S~2yftGsEXBPd;!> z=TcA~a>zbMEt?v^8OxYQ3Vtr69DGh8jRi5!m{A3353v|OJzVe-+_qJm;>S1_n$;%bP#!&hDV3@i};e*ABornlH5a*lS3eBssKX8hGRY| zwmHY53^h42JQSwrGKzmuYn42r zZLte$HH|OEW6f50|20ySBsUOrB=^0OGs@HnK4%+F;8?)9w#K;Y#*EFVUp{q=Gy28C z^51HBaS_TrA;a7nT(QPD!{duoYQEZ{!j+4~IX?xTQ`C!#)O$V_C%rDx%%^uA`dAUc^-n^Hozo{snZ6!Fg!M zBA9fcv!BB+wz@z5!y*z{+;xG%7pQ@$kHLs~GNw=BdqPoq9?_W2PeMS8EJ8qz6;}8# z#O&k_A7YH@@p59YOz{6L1DxNOz74YkL>`KOjNC_%hlOx2T)`#(kb0p{Dm1t7()) ze;8a&HNEjZ{kBl`W5@23vPf+jGqEH}ff;Qt6!C|#&m0d}s_C=nRsX-5UV4@?7C}wF zIg6AFdzqedw|}W(a5T=fk26xhK?T1*{u0OO^*;!q?(=pc036E zN=QOY|9Bd)oodv&lrc{ctX#EJgU_knJ{Ck7zbE|0^b~Xr^m09~f`Yz~ zLqP-``S6qwQl~`71rVG<{^D2wbYxxLt?m~=NBSb7Q%B}-#{cL@lCti>kpsdE_?&~{ z7LIWp*`P$$Sv26kb!3uY;RR_ApD~?lE!5(=Q*?`BaqicX7zn52pfaW+zR_F}Tn_C853mSES*=OlSARsFkM zfvq&JASla1c%`z`ffvfM5|2`>EJKi;6797etk7OX&d5=w)$loM_h>%NUaHnkod!}t z{##xzE>bPFa>*R&bBbDfg0?P$+H^lb`ODPW?!V-rq0_MGU64^k z+vls^jhpjm#R{~(3^*0&O)x`uI~C|@8R81G+6f)qT?Pd@nTs=VaTRbJ3C5Rmcp9KU z@n0&?!FiOiTn%Au`_Rti*l3BrMWz*MKx!$hPlg!B+<1nS!bPkU-kBLFSSjG0v|*!I zUiRWkNq1bp8-$gWXJ8|-&PcisB7nre!!nF@S|VpOS3wwYZwhi^Wxh<~i>V{n@z-l0 z8fUujVHBZKH+8*Tj57}N<&81u+7Lt@B4RyyhzwjpB-3L|+WDf7ul2x##j2}##IhNwZA#(7z43%H0W;Op<$QX0&8HAW?^MJ)T^@hc`?~jl00G0*8 zm==T0FvxFKPw)nvg#RVv8C>z+Z>1W{*bQ=Dr5r^j_ zUZaj=*RIeHYt$IF=nB19qc(6GjLE5e;$F$oY^}Pm^iP-x+Vd%Tom!p>*Q%z{vp8Wn zCwNokby$CN!o^4H)S%Kq9B9k|6Q!NaAGfMbE8^+mFD`){<#FAHmhY>>}hJZS$)I$l($*7s4aA?l9z4H_iBi%XBakC6RbzX3wDR8 zSqz=nrq=KBM?CiUOztt_6>A0i>Q#If7iP9MKEfV(p8e`dhXb}La%&sgrdIuDIN3kJ zdcw-L@L}~;E)Kh-!W@g6dz`>tUUm$%+m4~3s*%3fu2%Hj9jmxxb;cHX~g>9Lf*U5&1Eq1kI(j&?uZYEQ5}ZeyMEzMsAvk}^&9;I=5usQ-^@ zoqle}*9U`?j?MY&&+aKLvJ$t$`b3(dbU{zBzk|NRZoShwr6Wk(I^|bM{g-u$4H6*F zX`S+-DLwsBt<_{ar~Y5oDWeSkpLI%YtkU?40dAer&cLlxYL*EEn=neLY@jc9sI5)e zcmnrU=E^rqza4%|owr`5`>_)!C9(EmN}9o>oV2<2`mS2*Cl6}$XWa( z%TUQO_%coBETeGK2)$!y6P?SyjAQPDb1x=qJl1I$>kJ%wMJ(z6 z$I7PezoayQl#&f=ZmqM4%fXnz zFpC+%g<(A6!n$)QUqT9A*;tEBYnDM4H?3J0siWz)6>s`|yQ)(39<_93yp?@p{R26g zgov_kKjFSC)6jEta5q{iG>Y!*Mz`-9DPES7hfOUT-c@jO!=5(q?KR588^dqk%nt-Z z;~A_M#oNonD0`u|!;~LMU2JN&DGE%&uBUd1jG%M0%BK33>C9P?Pitcx-Mg)nr)xIV z-J2K5&4D9-2ZiSci_+QeHk0Yqg9<_RtONeTH z0Z~V!sH1T9n!sqE40-&Cv|hEI5xp;#+b7O}#6rEj*>)GIx(|wK%^uayt1XW!I%1TR z()27{*n^IE8#f>AMMo@X#5xV zpg|p=f#bR4c!71vKDD+f3sca&yj}oJ;^n8TbymxqE&3=%DHw-2^n)wH4W87C7*gp(DAJ1Cw_!RF%LR zY2bD-l-H8My_mc63!W|g-=VbZpgM~!3#ICZ)TZj+k+6|z-|ST+4LhV(_pDG~ydH-k z`f0R4PB^VRq>g4C!pS3B?c~!`$i(-%7QC1&(v8QrQ7}`g8%h(i@!tATUD}?lrmql`L9Blf zJgcgYG1X?;V98b2G1gDegdQY^EcGz1O%OVL(@(` z(E2yD`GneBDTOFjL!USF{DfNF#~z5G0(B3w4K7;>HdK2{oKDOJ729^uFqd?PE+OYK~FQZ{cG__)l^}0UEVWp zSRz@nw{`k=(AOFI!uM`e=cH<`F!28XZSUP|{Z6W1>sjwTwpZuWWLFkeNFy$(9a9r_ ziUBbmjwQ3}UHpDS{ni!1xI?j7N%%r8?l?$(k_6+zxT^^I%OJOX4wPOaytRe5s~g1B z^t}L9zrQYk8~}2B&O-)5y|f3+dN|(oNJ3`Z?+KZa85W$v+PLT@xL;uHG~~u7XO* z3P1T9KNJJ@Nl5l?720+~-M~`q)cvMfo$0F37dO?2=swTfTy!a2EY`2) z2C{Nn7vE9$Gt2k3gLm+bp5@@}@IBSWhHkPgzOR0wWA!|2jt6RU*IJFg5i?mn_@LM8 zzhBQQ9}l;^54XR_3aJ1bqs{#FG~^M?09&o6osZC;|5-=ZAE^cG##K7{8y0%I*HMHW z7JH@E(pbA1>fK;1#HJnhNr-wgHP@1MjN#F4zRtGCuCCItR+nvwkJVi|)^`;dpTMj{ ze}y_eQ9FC(t>90?**00F23f474&ys`J=vaM(R%9&y?p{RjY{seA6xwi_v4NEo``uVx~v0=x17ni@T`DXuhEiK!XvbVXJ zsQL@_g6oEV+-yZJ)X_TD@RV)%OLc}WwM&wCW2aA8t#g@>RM-KFdN=;Av?=Hla2kTA zz5$TJh+=wm(8pKf^h%swvzYGA=^CfMT?M+4`<}yR?5?ln&66nWmiF*{fdXwG^ZFPw zrX!2kkD<}8)L&VU$=2<)dJFfn{$*=eq~Zd^E`%o>)4?1plp;NoE5tam(O*24+WNg! z*Rcwhk3p3s2fogUPWHE--o!0#kLk0IQN@4MY<48acJm+A3kE&e^!&X#nEm#gx;xZE ztj6-5aFUZ=(CSn?nAm}ynKn?8d{^-XBOD)y8%d>F?X?%Wfq;;O|PU%hg3 z8RxXhD|q2X{rjku=|(v%kZi76ROQV-qoWGL!Z((IFvYoUv0jO@-bZFTydaNKS|F?V zl)_7CLCo=-`j*n}v0aZTMz7UirweJAUW;Qh3TeAutI0Bcr|WvHA-h{Z#?o4Q_Wl|5 zE3J)SnUCpoX{|n6wP&%L=FgfwqZ$fQ|JY4yUu6~E&p{8C<1Y$yAD4!<5{bu+5gWdvv?H0-{`EOb!L-yQ*{+-`8=UksPgshN*c3R`E{pkJ>6x6rsFfDjs>uu2db?ojVO7+kxvgDs=nTK|qz57*$=kKsh zHEOLHYr38C%WAdQusigstk#BAen>6KX`_r=F+vo#(AozdT4*%$dO&Twv=)A&Z;I5m z!Yut3=Hl028~>yoZ|AFc+IQTi@4b-8syF$N^TIMP#CX$|T3(CMu@!f1hfSJ~j(vHD zZh33jEc-UCs-P`qLpM?*A5>K5D`fRSh19=7TYa}S%RYM1E@ER(pedDsol+j^Iyu=p>_LU7BjzTO`Vyjy$eBP0VRTJ{J`8w_N)w;1x z*U7!Ic9(s2iJn&0DzLgy|%Vj$C?hMa&@#uOc_e8>ww|KCp3z?S3aTn zb+q+t=wWIUqJ3i=co_K~_#8z;MVCHI_7JU+dle8R>dTtD~#wQZ`6V|A=_xT)6H{P~y8!7GCw zkS#uIfhB@9zLdih^pmZ5GtJJ}v6&PUjc0#fCiRTgT2&8Db8{(Z#OF_94*<4>$<=-2 z@ds9ne?>S%Ba?EYwYKcW3@RU^bxUo#2iZqjG9qDBnYJmXtJA4Lr44okm=7p6x zG1H)jV_!H^taeoR@sPbcnigD0jVg|tMQ_1#U~TSDH5G)il!WtgXQkWtJdxCc?pJ-7!^ z%<&y4Fjjl&z3h9`ai;#~owydnv`7Ya@1&qOJR+mMr;c%2Kh|D~Fm*FMjYBfq zworvu+EjJ)W>iH~__WQms+H#3sSScL`+57f&3J9hKo5XbVe&_o$nZ!Y$&KujgHZ## zeE3!Zbr@br#t(*L%$N>#zMy}LuF-Pd_vRwx{lPgT2FRu9Sv!V=Qm@WZEssG zTgL*%*gkKsdFt4()s)pii)U3<)3pw0r6;S1bp+?yRn)bkcAXttX$$S7eX3*cN7&YM z)+*~*#Bw^=MH|gV52t!vwfQV$nJuR)S24?mQmO8U`r8uf-W@}9wIx(JQS)IzOL&Az z)FDw@>-i4n%q75r-+G)c_CgkuE=e=9J8Q^4No(%23TXAxO-sk&AUPcQG7mvGbJp0# zCutr!_9VhKqlbnIvu`9&`CeL3*SwW@QiLfw??5;iNrazc{mOrt`t3ZNrH}lSKal#( z2!+Xd&C)MG0Oqp#ET{X0aIN}`m9(H2#_>)oX-_Y$E~~MU?A(2}f_!>wDZTtgq1(7e zh17(L7pCZUk*AVub_h7T3DZB2wP8s(rlkZ0=G*yWCL8I&Ab$jy-5N;q$sPU0}YO1Sm(cTB&*hi zvxd64<5`6#6dwL%6qsEPXNEKx>4pl57)g`+X#RC8A%wi%#rc0o`4>1yPk&7W^;d;s zIwh%w{mUs2aROJ!uz4|D?39GY;Ggm6H4oi!J}^uHlcW#tP^fG9j5hX8o21=m*ON&P%M7;m$Ux1+!^}8q<3LG=hu}*lggj*CW{}0^82~Uu4 zKmiu^|B79GF#R!2JL9op0;a?@ECcZcm1+JsIx}5smumS4?X0)wASTWv@`uS#b4l4I zDM6q#l$4c{5(-LfNwG>w1StNJGD%XRLGhN9Pb9?xio2wAm6V~NR2n2nEhT9TNS=~X zUs5K5Qd&~{1jRay7cI(A)Li6Slf+q)_(T$4)!~J)imi?)!`rjWLqq3Ce9r=_4tLpm;?Jo&-th2Z|a=-_FuH zuO#lhh~5P2yZFq~n752TAU?Adc53xQrI$}@_=&%u@{a}AHL|%|wHA8U zx$j+U9p`IXbZkwC?fn9+5@YGXwn_`NZLaKMO*%%Ih4W=KJeh{YWVRMsChejz7Aq5w6%To4VFKwyDxpbUhApW z#>@~y-cRjm%X+OtxsL7m7SfC*=n9T}(DCVx;ahEr@A5V-F0bS6l}f1?n>qMiq1SQv zG2%E(liSexZ?$-zZD8ONwvC8sZTpLOUF0y8ZA1DEm^!_Rr~Vtz6xZYFiw#JYHwnxXdx1t|@K;P@u%BF17 zp1HF3AJdy1+9Gx~#y0OK4D9Sw6Jooy9;suRp#3uA4kcLadI^J69__RSv#Cx1N8Ho(%+1Jv0N5L(OgBU;@CI^V9xQ=*NE?}G*F%1ls zffXQbnGlzs_5k9FAnpOgxu2ajsH__CUc{~xLBH(QK4Ov0ZGkq;TgP%5QL{Z-qq0d6 zynmgOd2^VCH@2nk(PrwHE`kjEu&}ADr!V(uzpxFBXz0&af(>g#-~OyMXSEv9uRo(x zT?(fr`!O)@45uFZwaRR9I8EHIji^>DTy%$DEm8lB^^FgH79aI=yqEa$`7}NUbePm| zoBn{d7zycYD-UWNbu25=_WY36N@v)ON0U!m@p^Vkh^=J~_LW>s|CF}PKCA`mT%W!x zP4HE*ojalxy0Qf`=)iHUsj2e}7ku2tcc2r87*mt0`=>Q~S)V-eG(Ycob-9&I5dV%N zq_gnX3u#lATIOlhQYRn`!-%M93;M{LJHI85%y|2JSF3iYc};LS}LRysM{61>$LT zg$THYlZXJbpOWuez;}kQwn@%!TRcO&B%k4Ah>*uEg9?zk zXDL`cm=-q{iIvA^AfAEjdI$|Zq1CIACs=#w&j~jXUsiByq&^Vq8F)&F^9=c=F6}#^ zRckR{CK>XbOa^9CNe}S5fFJiiMjTTeDd$%t{RrW3cZ4AmR!}$1^XpQTe63k*S(&Cu z6|VfWV^ke!!1UqM4l7XcX~zr9*@nzdsRD6^N5R~lQ14flR_AM`FuM%uks*5m-hCC; z{_rh{B}%^+FkZG`!pA*lEM@e^gXy9MF<6zPRLLlk@wo5tO!l)J( z1B>Su;N^x*W(5T930VyaD(9Y{KHwtXB_VKrZ{E=d_xGNH0E4@rdWOV`$S3@^eCQV! z8an$$Zeil(qYqB()q4h0-BX%(w2z3?OYhI!!bI5K^~vWpR{qYMLD(#J z9FWTCuqd9u-SguvG~_15H)LUQrF1M{79p5E-kH+TcwOv+ubd#P?WT!TB24BBR{4_Zu#+jzR%;hE?0f} zem?(w{`fw=dpusA@8kDz9>31>I*;=_DKTU$T!P`uW-__5i~aPc-l3u2pNX*RKlR4< z+eGO+!`)BzG~S`hQqMOpO_UWq{FO5itWsQsFWtngTK%fNd409flTH|4Mc_2IF2TNa zhd1TwTkvD;Ch>x5*70%Yo8Qx3F5@GnjNqdGvY-@qBv8N;nMuiV7L4s|zq7;Jru|7G zi)R80(r0p4W?uMDzejN3ANF7H<@x5HwYPuU!TSC|7rW0Ry$xqpKl|Fw5*SZxcX_=z7^{^Qr)KHQ0HZYO@@T@=58&2i@*1GfpdFTk&_ zkFVVJ#5H^N+1tMHo)7u9w*2GW-i?)A>EwT~0$al54?hWSc5tQf#3Nf0tek7N+Uso} zJ4q6J~)E!zVG$MH=fP&3;rx~7uZwxa+*6e-(I%Yd)bx$Sr$m8E5Jd; z9K62JDVRi^oI1VYWZ>AjMfSXNnk3SAsM9egoJS? zi@Pk_$7>&bThPno>D$_Pz42K>VPcCyzapZ2?lEaeDSZ+{?1X% zwoQfj%^kzHlK4XFfAK;=Hw9&G znT*ovh92~1Icl!oigx@ugj_XNXWrQGK$dn_YBqW%>n}53H%DibRyX~CKg&?#msQu* z@#_%sLvEFpS)Lj@1LZ{(AaP7FMndv_dj6A z)p~~{tk8!pLwUh`xn4fFaGaCcv8(pmi)z{B_}iQIKWn{L#a4}WiqiwXKw|Ik+4Z#y z@)e`)n0?-^vDv{fN+rfbpPjak7=1?D+55aL8z;RORJ#IGyN7h`CWhNz?&If1X{LQ{ zpSM-3!WW#lX_8O>0>@4j`*4=seZRM7!Uq#|y60P;bUx)u_wmQEXGpA+$L;z1z3qC1 zWd_xnYgcvfmr*j9i09;7TXLb4qNgsD!tREY;%#b5xhSDL>40}mSjc*hz2;}{m@c1l zu3)`QY{JFoyzpk=V8phwPR@-!WpzH7^M?F4UybfL7h(4~?2Yp!pW_6;_ZB+$_kZtq z6;J$`Z|F9ct@hw==*}msfOV!P=ZeEU`*T+%fh+s-KX)X{Zc2U(M8DskE!lbDxnIbM zViq@+&ZlrOi8G1Kr|3t%H8+|6C@tAHn-*AOtso`eB?+kx2Z2X?ir>kMA zVY*?q;cUZYhNT(C_|R~V;Yq{jN}X{V!|sNC4bu%X3?~}SFq~sgdc|sS#RlWtVfdY4 zy4x(Siwxf|+-$hp@Q~pt!?+Lh(R4KIZ}!*hmBH|YWs4O0wL4b$y)uUakcDKO4r!&1Xa!<~lT8P*$y z_?yeHhoOH2AF^G?y?o66h~53T_qMKEi`{vgnpOX|G%M;g8>+mHfAToZv{y%;Z@c%%*aMF9prJaiY=jcpe)!&Kk%C@(i^j_4e_#<6wKYONGP93|xZioEF zMOA+Jb-#IUYUZjdpXZG_e`QGShvoD8L_N^jmzJ*&#$S`-Ke?+v)!}tJH1kckpKIo8 z|Cj}u(Zh73bTahkTW`{B|5nFy?{U~cxp!)heuiBK>kRw_%pOF$|Bx9K+uiTu&+^ot zsYzidF)0$oJfvr$f?oZ6)uC%I4;mGvk8UC(I$yg&J;zcAN3FA7DY zMyN4rQtq7>Gk@LPZ#PaGCN-0;%tl@BvsBkK-NpVed3I7B7%e8O_)lTHtFH3t*iynu zFNBr<+{?PbvYuVJW$#l@UvtB2Ph?*=cY^0dmwnwpYeA2iJzmuf;yN!imcL>sGi42wX59c~=x>MeB>f&J zGwSdWd-okyVq?i8)t|>lws(-#F(h@1-F=WXQTXB@t4Ex~*?NmEM;+DWL?5+}4zjvA z=}Syl!cn{PomLM?H_~wVoz|kxhwHqm6LI*SkyF=XlSgmE(a<@DkL*F|w6c_&ZY3s4 zy6ORz8b^I4yvW4QgK~@ukJ|gwtw9pM*Iibtc2duL;!E606PIYt-;tyC1Nne z4!b{LOGql=*~jc(?xtA}*V&zi=wUE)h}F(%o>Tp4RufO^FY)utVJ$pnFCSv9lKS<% z$Licm@?A~*7ylH$#Kd0%WynZA!V2Twe9T^TkG052pGW#v|CGMUq~G(W^mWGFaLk@K z)SB$ncL?dZ1?$vP)%&~M?Q|#Y9&)c9KD}U%7{cX}a_uVq;jaqH@m=T#zS2y77T>{% zO>s;6W^=5o?zOr(L$>B7Gc`=RB-h)A?zMVJdvqLTb$9AhK%5WATk=h%Joy`FIKJMV zK8)c-yYCog#r4fI{{MtB{B{_gfHFSX9M`{!;0f}$KlooL!}>5DR&NyoJYD; zB<0r-PyQl*(fM~XybDVHGYnrc{MhigVas3bzV})0giHP{?azl<&HASPsdTE?e1)Nhhc7mJ$Qt*-f7PI8+CJ*5GK`K(_pvDu;PNJO`i;=O+|w}GQ+yD z=^>NHh3>N7$*`t6&AyeqUZi}8j%7Tg1yzyp z7q|SaJW;;;e(PSVm}?tU`R({05!3`i;f;tW$Xv-_)hT5|tXZl63sVw~J6sGWp+am|aZPUV2`YH_5WzcU>;Imzvy@$z5vR8%kSC`w07AaN8GUSk0YL z#3n2e>~`Zgr1anHzT>RHP3I9Y0)MBI204rGtK+OzPJ8B4$RN|6CB&1zHHJH(6ij|c z$5}VZB<}H`HNdG{PgA)X6X!4tuH2~$?*CG`9S>5uuv7Lg4_bqpU(Nre`^U<;RZsi% zaaIc{Z|ZpZkwtyScuo#-?jBE4*mweq9K3OYc8{B2br$!s3DyI`a}zASBEQm}I+1$A zjT5b*!d4Hlc)`IBvB1Slb*U~WXQrjvbKKf(FDFdmeEbjtU%E>MzKhpqn-8*Tnp8E) zj!uh8cDgJxT9uTz)Wr;XX!cwyW_8J zY(JE3wUx>&%C_1G-^jKSol0fX+VLI3Rr8d;spibE2xgd6Hc$MM!c{X@stU^vO%5^s z_2S<)R7JU3s<31ox0C~mzmx}6Qm#-8*vlvD5w&r$)#^H@L1_S)#L=#sm4EU($3bVecZVoU9sjU(vGiM?hpo=>89%zzHk9!XQx(74o=LRp(rR7mK~y5avOLssotfFl@oTfs zrPi2a5+~RlNN4YR*t))zRL*HQr;)n_A6(xYYkGY0!VvWvDx0Hg5pdgI=2(~Xs45Im zZ!Zl|4JJ6)9pAyL;?m<(TuO5lx3g(|Oikm;=jWXxa}XNSj{Bb$tik%cblr`{eY=@eovihwY#PuGgPfb zv-2q>EJTH+w0GPm@hcKPdQ8HD-GMar=Tli)DB=)VdJD#cs>NBMDteyXZkpArqqJRt zbgZn%IT0#(Z>V|#Xr@`+JlQq;x8^^DstWtlX;$kX=kaOQMYoll z4OK1q5Khc|a^PD;S2Q$LNwv+CJ15rhA4OOj36tw)!W3Z=-|rvaHjLrjLCH*}*7xOF ziSZd1g{j}rcqbk6)bF;R$+a$uuk0MA?(T9SIN-KF&$a#@pWHi4Z9?@Xb---bN|2vY?TMxGKc*d3fU{^};GQ*HyD+ zM5tcKKQ6V~Zu*$@K)j6MN(NJV9-;KCzE#B>i%_112o7lRV~mb^9;|TloKopiy3~N% z-u9R^BEEhq-Okfj{sRiQ?du-5E*_h}^VkEBKll&spyRC~&KVSZyyCuMZlo$M&?W!T zt&ca5&i?dq>!wyQ3nEo_6t-9=x!|_D`Sg-7)MvFD8pE@g$tcqwFWB8aOtsHt#%0B- zI35h`hDuDlV0Zi_k(^CChBbF3gk3lj+B<#LxOnw`q-u#$mgsr}-1c30R+spi4g`sCP`^Tb5COM6e3sQZzLHl(J-mrJ!vqK1 z_TpJA8~)RZUU9pqgwfn7KsENhS=Pk^#C!_Xo78`H2ci=mAJ4={X{x+CBb@7Dr_wDM zt-pjMGr|Wwp{MkUC-hW(`w6SNrz+pAqULcE#XkOob@3oESE1^q`dI$#4n!wh{L5uB?v&~I~`tT?x&CKWQC9|!*LnS_=Q{}(lR==Uq z#FxLDUv#T<yB!+^Ul&N_|(VD{`jP zo;=68%`5S<+eE2v&)Of)(RXWpnWG1M++1#w`5WT5_uQ&QrCaUhfLc`ABj;M317Yhv zWOYLi{>Q6+`p|xHuJyQ2(#dbO69@PZN*%wiPJ11e<1WM91GoGg!#)w@j*p>ncShHH zYur^4mCi{n+23i~_PNzj^aSMy#r?p3w_1%`{#=ovDza}VzXX;2e7<$_rT&ByzILk@ zs`Uu_7QT;!G6IDjd(vF1S>Sk@e#10E61?IYyVpExg{<a+uhI0O!V-Dee+-!pUdAVALsMhOa)Bd7;qSWqz9<>kMbK36nq}46H;C7E{#D9RB z`Mh3X0&e>sPg>Up>Kk>xM>R)_{q=~AP_Zlmu_=)%wtI}T2*`0wB+lc(@ti)=_XPYy z=cQ2|mC8MVS4>_vVvh-OTk&2MUmK<3bG-IVi>yXX{f$vL#-mXT z)O7UiX?xWoZi_l+3@Q`fg2i^Hb3ystA}cQ5pU=c`9`!4V_}xrs`}2G&u34o&{LRT8 zHSb}MO8DLG@f5dp{r=4+dDKvZ|E#C1#KC_5eN#QEYMMvg>Cf*k2Ij~q9+iu(_Q#3f zHgES3XCg|&Ezk9+Qk3(%eflY@RbbHnYdVAPQIDEWx=i>NovI!q&Kz|0@AiNKYfvEV zt+PGqZWJi{=c+EtDPQo1xhgCE*8@^IW1J1%sBhv zCDt{8QF-u7kNOV^6!sSfIQA?4vuyO=#aT!A5C21)O9}s*j$?nn#JWtDt;SF5vIeN|)owx#-#K2X8?U+(U3WVtN0cR#D|J)9&zr|n{-?VNl% zk=JU6H?FWcUg>YeYYur;Hj3ebPUvdvQjO^a|6lgK z+NvtG?2A&Z=HYeh-)7nWT47xhQoYh1@VwP3G^G>Qab#2iPg+be%@-y zBlzo{w_1l5`Qua&r}Rz9L*gt>4zpwWSYdX_^Hxkq_Nz{YF6D&T$*ERYc+2(vxOT#| zR@kx<;uY4~O-rmLq3$;=`@QR|=2jLN77#H3rd~);)!T{=54f*)RhxXDx5DjPU$8Fm zR1^O~W$c0%tYM)AZ(57nH(z!#D$FN`e&gGgbJZfd&!YZiY)ZdnsTx%Ex=UrRcd43n zE*0~xi{iPJSIMp2_i%rJ_~d5+DnT_Lxm4AM+&tZky~(B0xItNpf7KSkMffN1?yh{v zr3zK9<-z*WQU=+-$&i4mH3U*fGD<}SxMT27hBYL}=H1N%>=Kkm0i`I0vy~Gzw*-N6~z= z6qTSgr~++5pV@D{WQ}okFK@lldOXB4{*lS|cb`0Z>Xqe-S6NM5X)4V;HzwVig&h+b zrP6q=!2kD-_^Bx8Sp&b{9w!ZcL21v49U8@G@%`^Vx~8i;Qa^#_Q~&Fau9+v)^pk6M zvMFjj{{N$E44MBo9$mYnJoz=N$nC4@qaXQ7tI|(1l^S<}q4LvAmQ>?TFqAtL{&^&< z8maTk7^PWnSdgjRYP@EFCO4iYXpc(6ygAw(Ggq_3Fg3sY)iUe0%YEy{vc9oDR|&rw z?@~RnYhb%c+D?EsJnT}#@K1v)rf9na@+~QqJ(3k5Xs=NA3{RpN#1|$`WBtWWhLN^Q z6^|i4EGuIDooV@0CB~P_@sNVyvJw_>?BLBq*+i^)$)((E1PWy%unl(bhM;T|zO{;1 z3Go*$|0fm2E`bRw-s8oFpP)kQD!A=+A2kvOr>A&U|JYHS8R5UyQX%{~wWu|mS*o$+ z46~QhS3S0z#xgmbx!K>7(^_**XKk>9_xWW1?-WYMU)Yv2PnN`iAER9C8Xv|ePDdLa zCnI=**A@#1kke5lr>r&Da!T`X8rzI5r?Y*WlB&g@Q_<6$LmRN=T zTTXAQksPs{=BkY?=hYsZM}5(w$P{B45?fBL&vKG&$!?vTY&RkCmy_>yPRhyn%gK2+ zC+U9Ja{M7=&0yplTMw_@!&nf1=-*Zp#(hWku?Z;bjyho{eD6}je5Gk-*h#kC>C_9S(+)oSOFRVnh*urzD0b3p5jVctz-eB6#F7?4t#sqd1 zEIaN}N!XRJQ3G#%VaLGXzDq(>CXNi)Z*GX1ft?0_M@$dytA?oe=7*?4Neq+Nn_P(< z*q6kX{mP;z`QLxBh11xiti=xAoRm$=)GZ+@hRsLeS11YFSA$W^&SVOXz>Xxg>{O0! z9ICRhg;zFVPZ2v6o@f@T3b7MnL)EvS%H6G%aU%At<3TKrv$t37fwa> z5(l~>SAO2$rxPxKE}Y1joYpN-4$VnhEXXYgjGY--*! zI#g{Sj_^rTg)KaaYOw3!9CkMAC7&@q{}!j^Y;_LFXTxzG-2oT95~_M*7r?G;ZKh)f zZ+XhrXZUxaY6kwoL{uPg;AplzORxjmpV+buns+8tZN?Tp&*tZ0ACBN%(BR!o+2#Cz z9nPNYMG6P8lbMbk*wMt6oz5w2Y35-I%g}1W?t8BZjLzM&w*Q09eO1PizXUM6!9+uz9 zXHvu;){JJmmJL&3Eqk*`*nvG+npgH}pF+Ly7Z#v2Y@shVl2&K^&%UmNy;{)#Y&5u-v3AnI# z%dbK9bUQy4siN736?R9xu~T6aXDfTTaVyx&7Jv8(+KOEY z=af((Y+nIJ%8QZC=`|H5zZRo8^)i?*E2LJWU_N z)Svk14Yu(4Batc#y9B14rJJyYyQ1BWT?0F}Fjf>4n5uK6pmE5 z7RjYjV0)JhS=sj8ixy%Fe?leL_0aowx9W-=1DmmXET`-QxEZyY~xw4&Gf3-g%ZCY2T;gXbutxFMg0G(6EKqp;T;sVJLoGI0Xp#f#KM~3M7T` zV?*6OQQK*7@*KW)j6Xj{9p< zk^*=eN_AL4rAXWfrXlec&PI}v@UG|C{Uy#2_#l!v<6&e8U4_3JPC;9-bKybc+lAvW zMsN1+ouh$wz35gok`dgG+SuHzgsr)WnvUHD-h*TnlN+m#AW1s|evM`mry90+Sy!$n zoM!AISRs0pu6fz*Q`N>%1E2XP%|+r;czQKWjeQ2Leue(T-VP5SDXboLeO1pIVV1G8 z;aViEQVLI_icIo>7rmwnPJq`twp{;X6d*Yo;U`EEZ--6R=mKJ3UnB(&gm0qFRHzJg zeqE>S3YVgoA}+&W6_R|a;cOlbNXB0nwU*W;Z8V(X;~$y#xo|O(0t#U$PX~y980>*0 zqn>awk~lf=pT;hQm#@R00*1i0>vh@$c%wB;9mY~;5H8K~NaBO62QaI0F01m~eT?1gY6k^(B> zE@KP#8@mp=Khtr9vRNVVg%^KLH<3>g{0T)bXVC3rJRv!-p3pa#eBODjbx8dC!6sko?u&uLk#t7}T!$o18T`uF)$qKw`Th5mTV0Br z8o`H=B%T3(H2$^lhiZ<73f01u-!Pq?wH!{`O##?B@XPPqY8ZAkjQD}B#CF4*f265N zI}k3ZWtGG(gkRLs|59)Rj_>x95dk%D%mMA61%Iz&p~3$QTyjva|AlbeAu2SIB^I7V za_;Z?GgA~vo;mO}W3Pd;j_CNa;Wi|3w)-%e9@UOmIMmp~;Oj_Qq7+)kbo0i->ycas z^n}*($d{sDjy;gmFTsILf&Z?V!(G|*o z&!G*^Q2^YFim+?oYYi+Yq+J82oz!+N9B@k81K}wot&;U07PQkm-b8DK!L`ONJ2PIr#4q|8u&vGU4L$JWy6lAHyxm<6IQ=TjH@5KNCc5Ax_-`aLVgvk}&(e;b@Xe;$E`x((wLJu$Zm#V!u%IPR!B9D2 zWNU4^VMsd<*9kN)Jd(iUv$RS*e5k$0S#Gmoy|IN&lRRn&@qMuv!#jFZ9gYmx^b%du zSojW-8&4bH2=;Gf#AZNG7i~ww14!2MI+)v4+rre#v@P6@zf8y8-&HqB|Iv zc`&MnwqxNmB-a7OFyn6?b%uO0{^s+jglj#jBh=yQqh5M2Gj;Mnz`f0l*9D$@IvY?xXyvF-TAVw!N16z16 zl1Rf~`i&eJ{=y<8T_F7GCMtw~H4N#m>Y;m^iC3`g9o{WIWcw3W1HpzjAB z6FZEf7AD<7-#^c&hBHwm{%S0_+wfl}Ly0AUVnn@OP9-+A}cYRvlmX+ieUy zrt2yA$nCTiaRN_^J+D>*1UCdDLd? zGWZjceyxSgMreB&d=<&+xdv`W&H#jmjV+AJ@R`2J@Tk5>j;0^{2ub3tu=D*MwTHsG z!Xl(f=mI!xq>hsduN$SuN+z63Bvv@rC^-cvJ(naNa~+xrOiqlC-Db zp@-=I?L<0^F_VX-Wv!kKccJlQDx5J1VVA%$lUab|!UUE+%<_r9a7qqGgPjYHAm;$! zjZ?JUA3llp5T^icM60oDrZE50xw-C_ME{~#um;(lFw}Ty|JSoW7I#c*9>6?x;}c8k12<-Hjm6mTngLF)J-kyIEzG6 zi37)?*~A$SuYH1+z)pojkuzQ4RAcADH;r8e4;#AyUOt-^CT%i&(8oWek}14=j;>uY zd}OYkHVfg0Xf<)%`5x|s(-PQxPeIK^QZV0GP<$f7v4uyF)5mbmJZ%@lQY7((mB#jo zal$xGLHB$eNjM%!vkPBA&UAteNDAQl66z)-b|&;8DWCv;idw$Jat@0YabVcOT6Bs7 z5H@>?{+9%?PkGcbB+F+J{0NEvR(RUjXJD5C?a#*}RO~X&a%7qS*RAoWEbK}+=ikJ^ zJ_GOHpevX29%~75DqYE7MES%isHE@1-`4?dcmrBUKsF5jfQ19w4Zqu@yQ2nn+pOa! z!^e%C2X`2|3VOHbiblgaR7gI;$3CPhvGd?o6zv#fii;dUfTtT5^;9*f048s3a* zum{4$s0h0d{`wXDzX3-Bj`zRj$^?5etVJ>ogx^#%6Y$>yum46@s2}_Xk_zR+J9lgU zboe_G|1Vc#QUiro)RKr6Ac;W;!ATODP&MFaDgPH-cVwY?IKJf_E1CX7F>SJF0c zH!edD8a@E6AUav~QUzixB{gdDzAOA>Gq{B|pUe%RI z+Z%b+K_p}1FwEi+-2V6r=OSm&!Do=9Er#DBx$fHoe{RA9io`z*ujR4aV(e7-6J+W0wUi;_q`b_LF*shhf6X258UNsy4LijY# z`PP$9A?$b&U%kP<6Lcr=VGwNLVN`)F+|}Oe)7N+Hz3SaWuVYujWFErJ8_g*azJRup zU?sdENmsN#4B;VQ>9R05933Xk4EO-=Wk~mB!A+NFdo%2ODP8aimvQiu&a@(SMi-w~ zjpAwHG#r`mERv-(<}$Bpbh%gU!9NBTUBPpr*uuxIq!QS9@Z}ULioF`1xZ0~qu}{If z{_b_Il!m}xuhA84fCYUh_*G^KoO3M)=HucbA7dSozAS@lQ)xOP)xq)CX@B88eZ8tT z{=?voepDK}8eV#X9ur+*ma&Dqj9mwh-^7?8egm9$Gw~U)3!$&)Ej$-YKq`#A)vMaP z#_1R?MlzrZVbX278HEvP)SCEi`0*WNMEvb=CeJ(9;?Jj{R4tN&5vn`2EnIOISKdI+RCrDIgb)yqDI%&Vim`xAHgcik4fCrHK zb^PJS)9HV?K-i9P7D=I1tu8DL))`yaaXsUP zIGtdU?@i`3jvSa+rVC4gpBcLf-u@O%&n@;exVM~wiC-_Qph>Y);iD)Idj{N#qzih# z<5jc%O$*^4yTPm0An88g=6Cfh^F?oDN+1as27A1x7nz>$cT`5=Gw{g|_^1#^TmYAC z_Np5Ei{L$5m>t-|;Lk{|bPvOJAL^Nv0HZ&qb%`UC=kmkWGI$}+>-(Gs_T|C-1)oqO z0)z|EZ0z8N{^jBS_jb@^_zU-<{@68e{b#zV%iy3Y)(HmnF!&29Bo5yV<6wD zNLvK0pY-^Mh0h}Cf@0Y504+qEPH-LSiCqR0>vV;Zp)ZYpWCaxNN8^bkA0vA3Am2vg z5<3rmj&ku&KE&A%B+d*Fm4+RlTsP$j!v@+~&`4qL$kR2pv7 zHqU=z95Deck9pO7C^w7KZoOA^LHQF{!{K-&iRCL<@`bF*hjHBR)q-=es65~WR`p`OA-j>lUZU5<+E903+2;UVhiQ- zSz-(26Ix;m z<>Ol7FO&~#i7m`Ew(xmlSHN?~S2~$_d4j=&qVzQ ze4@0+Er;?F`D|u~P+k<5I6`?DTx_Ad;5~zZChtYd`_Ho(j6!)wS>g!g{baF)@*Z^A za#{Z|FMAR(y7`o5UK> z#SZo^YAmt0B!}I^D7Nr>GqXoA-~ZpwhufX^-n=%i%58oH$1#^VlNyI5AT}TnjK>kU*pj=DmF2R9Xls>XUDFIp?G{3);X~)9*2i_ zXJbS4?lT(T_;zGmq6<5AON?O0A7}7m7dGxZY~WCo*?fl8cmJZpt*i#k6|Hv7C4DTY zw^r3W%aaOrR?o{>S&h~*@Yi)xLm|%1D%;*FQ)6Y7dBEOk5JilwX!S_IWBrO&x22uJ zh$fHBILQtnbh4U~l>GCwvWl-eeo+63{jIE~ofHvK-pcAU9$!lxiEmBhUHV^$l~r!t zv7GvLQ^cSQt7dq-Ev+NILPhB`epbqQP09&N)f%ETOIo$Z&>{1ztu9_Pq`dSqm~;gN z_Eu(dhP4$v|FfKxA?2iBK^Rit_;(x^1eH3k&Ck8ifC5i?&Up-eg*-NM9#M#6JgnwP z3)OGQgKJW0j5kGnKR2t{|4T1P_NXKh@dK+*dx6Nnm{VJN%2jc$;n`8 zTGI{=z8PX!sy{NM+f60M{(mz#SKL$|*W2v=UP^BE&0*1EW>SetGnYtKH7wlw6?-K@-X35XEOlg84CC|EG=U{18r$F*-kaVz9e=;sma*M7?j8CNI(Sc<6 z5NSu6kF+AX7l~^ky^pTu(X0uwF`8eHfLD>m(}uJOb`i!~hP3I<2ID33kAtPr3mTJZ zO{9@Ao+Rk8v@ph<)HX=FVmgzz*Cf(8zG|}pG`2LcKT-u$2IC2X5xs2)xM<$fNSfI> zfE;QkWpxfFh3%!kI#;(%jJ0PW;%9z1Qu2+G?@E*rA6Z_1r|!tht86fFe|& z2LcTo`1UHLNt*S3p4s^5dZM3dj#Z&Kx8wAT*|fH3w~0K-TDagRxIJpAd9n z{eA^*?WC)*b;!birCk<~@sUz`m*%8#q;#%J19CiyjZ&kerd`|l^yyC>b^>R4_C9g( z;>D0yOdC&Xb##RBcBKDtbF==^=B~|M6R)7wFKnmc8b>&r*EisH`k4n`kv?^;N~ScB zoVx8My~3ok-8{&*ds0ES&E!NqX;Js;j%(_njI?k$($q#U;BpwxnjQN|=epk~?suf^ zJ!({n>thKHKTB}bm7eq%PjcEy-FkK;<~q{Wo)^i&!P3NDZEc4~a;Mifw-_v)?lq7M ztS$NXu1f-HOTBxaAPxN`&p!KXJGJLjL1wRk(&IiOiK>>=sqZv$qNa4AZ(SnQl)m(h zA<^BWj&X71ZC7a*9u{|%D)ejX7!-oW(O|7`(4gp3-7jlczkGF4@7A2Fr};>4tWyS) z<8SBeSO|EU&%7!sLO@V4$ts29Lovx_PU2WhGDRUNf8N4n7AN^D)FP;hLgI%cQqCZq z?UiCwgWl5BK~AGIGVveiwRKdff$r!6SYsCaYR zZd~`zr>Il}#F&}t$1McayGi$lEwioCn65Gg6ov*oes1F~tsdTxY&$7k8SX{qoRt0= z9zZ&s%<>)KE|7XBq;?};lkTok;HXB#%T*dR%BAX77hL(2lVd~sg~o;U=@-|x_X%^Y zQ^?fpb4uDcDw3>ok=~A~OpczEtVg#dt@&ucNommN{+>o>8k%Pfsksxo8&Yz84JnTv z8PW`eFEH4zm`6EFzmN7IZ6c-eW8BH=6O#X!`b5~D)pyJaHR4+ z93|S8(yfGVBu6LRoLY@6t1f+>+KR;Lq~_BCiK|YUIBk$)woh@aj8$S~gRS&xT4OTY zR`Qu1;^CKEiWaWNoL*jhm9h~JqGe97hwNiZ2 z6=IXkpi;A}L&^07(prPi`dL+HR}ctMXVp$Y&p#nqk#n2{a#qM1l8WQ)R#|iBo+GOJ z-?UQav>s$*1FVuWRW)!}XMvZB;4x-F74oP)t%j;EOhEuQ66dZu@45i~dxRR_~=ZOYi$7thcs`G(O6yi{=bT3qNM|&7=!ut=})q z4?kuwbv;JgK9w6;j(u+O={%>8O!{Ry89B zUrG~KNsbXOwaDmpKrXGlX>F|c3g%UURCVy2QDY}h^D5=c z&%AiPba_n`vgx_>VvTo$jtIw!>1ht=ZJV*;$!$(I2hWMyVd* zanV{&)e$`YvbL7W4&C-}ZC%y+f3=d`I)CC=AO)|BB0mXI`a0jHdEcmh4rq8$XKO>6 z+tmIv)zW=(&`0K~Unvq>NxDxi4FT*X5oRrR>NP(3lHJ)#OV{rucmK@FT5m0ot8=9z znNB2Vu5>f=I(hoL^z(*Oq>o3|_>E}-S@Kl+wyCY}xE6E)&PEzf9Hd(}nhi5oT3a2U z19KNd(h7Taxioz92qHg`;I2E<$M(c)uGIC%1aj;?N@?RU?LIm!EzpoQ1^qe2PQM@h zXG*}m6?Gr>mj*voj~-1|+&q*nqVy7FRTC0E<%-x)3sKiIW4GzO&N4kXE2#^sfVXdlQMR^A=Y=KxjWC384g*U zcj4OXy(Qh>-PU(W{r`Amoyp>niHM{gF)xtX?-@aE-IQAX(yN?hZ6@4A!=0soy;FS4 zVaNP#g`LtZTwc}XT>7U;SNDz}(KnFG0P^xzWpU~Wze+EDiS?aa=RZ7B7Fc-nL?qSZ z(mZK!)>YE&I$N7z`%2d4uWQnp><(nhHK`!GJqevAHQtv%9$rNuVeVJ|$I>J#OXGGG zm!?Li8FXdl5Z1y>WK_;{FvFv;}`y9kR@#GBG$?|A?{{82I?LjL zWr(C6uuhU{9UehGo|oK@maK(zo~?z$ktx2ly#K=`FxkRIhe*n0R-&}`$Otm_9C8^z zY|pW^IP^~jr+ENAD7+4%zY zIfs4DWSY6wH&5Ddsv0rnNvBTvyS#jhRn6GW z8ut`Jl>cdi$<`QQylKAiR_(*Bi=?*0Gx^(%p7fHM>y*uqs@~=zo zXX=rDH>6HyYLeT>q-kgRlC{4|zn!V#Sa_|td}h*Y#Qd**OtLvUf)rkrCZF{pH?B%6 z&-xR;Ytren^;Gh8TA(XQw&$Ekoug9qb4wZ?WgJSX^N=RIIxnN?>_VfNS7!_Rwnvb? zucSY}soc85h)vDa&$$cz)q*RTc38T7zEQ<|>_?GCykrYC-ik0@G}nJCxnF2dH5jR1 zxEs*sl;s84GCAg#Tyi)ao>Q5UO`#|Ncx7wg+Kf3CHPGMA z_hNn5pARCdDwNf`g3{=x1=1J1R9!Pzs&y%wj6Wbfx>SvHJRqqrhgXxZt3(-3hf+ot z&HrFGWjaQfDtUA;*)}pyFhfU`;4Lk@Y+dU^4)U)-`L`%DYaPzQ34z#M*c^AWlzZ8q z{5DW}b$PO?W{y^RH_DMj43rYD3{m|k^WnJx(l;E|RE7})q{RH`q{n{gbADCQY`^4u zwYKMq-_esM+vW!244-I2T1VW)ou-{QG%gNzg#-FagRaJq)%zs*>QvHapVaVLBN7)c z4ZRjcR%c7{H3Vi$4X-1xpEUG30<$FfIs&t#hQA^(P8#~_Y_jne>E*A1WJ6!6`i)fb zWUsX2Mj(0INBSK{)%HpwZw3;tKGK$(0s7i~X-2-K*Y|$rb{C{SZ`L3l7bN|y8bsSi z3cS^dobD|p+-gbY_Lg#P4b=6-m0fI(#ZPm`!;;_a$z<1)tjyc(1hVCnRPdWe+a2P6 zQvAR`n%K8_Urt9n&2lTe;9AVZZkSY5L<7&1tc3NW9a6_TsCQHp^&69#hvUR9TFw>)Nbu1*-*8yIt0*7szDMDh0itp+~IB z`t#*F+&_n9&3j#ukQckMR=@pSAUl>xv;SI8$}f|=|87sloRG%+?M2o|($c@jm%n`+ zSs1%J8;Xug<1V{NwclHN^pGg54_-Q-Y3Hn`OJSVoW1ykg?}T|mODXn!C@~zDmcREV zhnh);-q$9kW?2RABZV$-fo9n02;=3{+^L>X{--d7BULA&R42{pxyaQ2BVO)Cn$!VN zsxvR#BmK|NA;q6Dk3@Wg|37pB!=I#=+@9vHxl-DP-K0g3)a+wzQXwd7=*K9bi_3L{mwBiEpK@j# z`v1%6gZR?+D00FNWv%=o3gp!SX~WkLGG>AF^lNouSRj@A){V?KAPxA|n|K_Mj(zhd zcN$4Azx_>i&X*ql8$#;MXO!0SrS?VLNDEooSk#+5+%FXs`IA)*GinQelTmZQOAtcH zn^Z=6HWd~KLO1d?8=eS4Z?ZlcS`opY^r{adiI7pQ(;T#bR&wB#+4_j<5hCF~}jWtM}4T);Ohcy2MHmQY1w)3K*#sfJ9`;8f&4sppRUR6~$nTilzb^me>n;#?1Tvp%d4_miJ1&eZ$x%=g9v-!SjA_D%TCyQ1Y9fPgjQ9) zoA7THIkTeRBvkC0!)~({iwHje=N!<@p%dVhgRsuw-A1A8-OS_ySXT*I_HM~17T<^c zsTKG*3P}#b_J4QdwucP+9fi}5@jhHRHp66xTUE1L5G<)ItaYp#Sn3X_$qMZqzo`=$*$=Kc3ELe8q^r>xrS9MMm%-#L^mYvE%QRK)uhN=pe%u$nISap4 z{@_sRmaNH6g{Z7bqO_#B7x5S+>s^K3uH<-U7}-czYX4vs#?#j2EjtAY8wC9_jKX5*4;|r5knn&6Cc?I+f?HMRiz-Bh zFE*rpn6%qq>Vo$&O{Pq0f5+?cqozV%tii*eRdd0)V(Ktv-6M9T6Xj`6T?WIN3oGjO zuBgJ@wkNHNrVKh2IV`4bYK;hbn;dPjfb^kIuZ1w#@76To`#H!l525t_Ih%mvm^`@D zLij|6M961@1<;U7ZJ>V}A=G`<8(N17S+<@;QMj8iq^m+0OWm_86q3V*CN=-EwzdlRfY;?|^$lqr=7;vyRw;!=`Z;r`J;r|4 zcz-G7gtd8!8$1jbekExy<$Z01Rsso2f)DM4M&yGH)HVpd0ki%=FQ*g=lQ7>enXmk% zwMxyMq%j!Jyr_ydAMA=8Gk?Y$GwRKLTH1}Tm~Y>Mxdy?Tq_l*e4MKS391VqEN~>>v zqGvixs$kx%0Wm_DNnYNCxeo}L`mjDecsu#-#Od_*%W7nWhE5zr7d-@b2L~OXYJ0(%jMYGs z_JTWEQ69Rr7kqxGg?hc{jq)O1Qh7J|Hy-bCdI{V5lx<)ra?*xVS6?uXMJv$(M-9g7 zCPO*%EN1itDsY#15MBi!Zlh@|iAd{j;LPLQT@42TbURDqrpe`8|co zq+1uRau3{)6sz0;2c=c^@6S~ZxWHA;?JHFCXg?e~RlrF@S}M(Hy`84!7o8P;V`03b zx6{@60z#bN?Cp&(Lt3Jz-aaZwZy#HqJSPMLS zJT&bmxRINmp+`T#RJHqc{05AE)8&b7#8SWs@w*1I?hg>+h1m|DF0m3`%(>?81Re~+ zX8e0i5C#h#a64Y8)Kwf^G9W}JTkvFO4T)ES1fkW@Q9=@bJ;ZI4Xb>C6S4 z;DkAmX=U#aB-AG3{((`01m_;Ul?l~2_XE>-EGIh7Moi=I z6>Js#G)ECe7ZZoKDIYcr&q2^x^YQB?K4q@l@GIOOgu98g)n$yE-+W2u=5Q}vi1$wx z%Ud15q{G-i4;ze{DF~qFet14XIj@iBV?_A}lh9QlkG{asg+dsq)l^n55+-Vh&j)$h zGNFr>#MOrU)xtUw*Ge9{Mo3fPEob<$UZ|1ekKcFmd&}&z;EPAu@da104F2b8Wyg2@ z%Z?All^vIF{N4CVQBf&*keP|5F9?E@nYdpK^M&V`!Y=o05yRYgorapH`BptTFfFEz zzz*#(CWOYW$4z1wPQZ1fUjY=FKUdUR9Y{tZ^BhDSuu`Mi#@ps8oDR!FJmM&G+$`Z& z)8@E%l?O~Bg`2t8{+#&eJ{yhUWSixuQR_{ZwxJ<=U zte=#G*32GkH4SNa>xve3MC$D$eTE|8Sayz872$L~EuqSMS}_qilS8*7G=-feDK+cn zZdS80sT#D5+tGDmQIno8(2|%MP=WRzs?P#ErTcHDPk4@^PU0SVYtLo6Fq2JD(dL&pMxm!dE&O%o@wC`b zrj%mqksg$fpXLA(=2@1)*`kmnPDOU!@uzK(`%2VD$PbmaRyAF0(>|3bd2@ z=^XKd77P1Ss=2{<6~VGMcQ5;f0%8Y@DD(W6{f$u6CuD zgc|6^xD}_VdkJ&49%hq;G2`3G8y@Z!T#`25!HPHQBsHjCZ%eJC<*v7F*&W67fn~fA zX}lMUj_RXFje7 z^OH`4br~R=*zWJB_cu&HlG1^sNHJS=v!f}S5Z-1Gq5%0G{5I{`@*?(PKJ+9(dd{y;Fcq_tTv0&xl+11|AX$`YDmlxf{3p@$T@g@ zTW=kB91t3Kr_W;itK)QY5Pm_8vTRo4vuZ}$Pjo*MZLYEiCL9pf*j!3xghOV5^FhH- z)wUNBsqWASk2mDKsDN9JfNN1k+uzKc7r=~z!rUr%lGua^IL|zHDsAdB?E=n4nu23` zg4-csEIGCs79A1-$oWNZ@(|wZ3=f8PhlDtiI3HpT3l~YfRp4<1cQ!AULhKRYEZOh~ z+>Qz^1Gbj86v$}2@q?kUZwAFE--QQ?NJpG|QJ4zhu1#{{pW7zAO7U4exe%ZfDhp0$C>HK-c*PObAv7{lFwUX3ehmeD_VMo59@pgq7AZZu3#2A-O*Yc zuo&+@q5}$6C=PgwC%i+fpwle1h~kk4WrdQqQ&id!D>heme+9%G7aW|dDNWju#hm6W zJ=p0~D`5I@!GFZ^RmJ<5)p&|M!j8_yD|g&c<)ZIGP>UsqK^OKYDY%OmBz!0$mvLkQ z`eY?LO{FCO5tJWwDKF7$SIPD#1c})Dsc8Akh~`SxQdNL`rv#7T&Ita`0yr?BWdR&H ziLwAr9H%UR3&$x7P=(`4FF;`wTYx2`0<=6WwCbC*ti*GEx>-2F?#p~@aiC@f16sUV zNFC>=o5Cq`xT~2{?KB%DW~$=b%@W)>E!2;1xSWcJ%EeiMc*>m09U8=jr5)OY6HtdX z=Sb?%5O!*DXlpjII5cdzJp2sazfGF+FSCTk5l)$lBeY~bjjFUG$qcBO#em;M_Y6+C zos-PuB#LvBIZkozY>rc$OXZ;ii*s#pzPWz{^X_M8aa!<%zt0Q3REz%A!{WxmD6dwo zc2;5fHhJ_K;OVHMqR<>#xoHjZq@es!@`DS4pFnPY1?x-rtxU&}a{MJ>kU-4C<kAr50$rG#T(ot-~W(5JrU{(WYS)!`Air=th43i&xBxs*gTVO{4Pi;;xiV87YNB@<7;?XAp9V% ztYB-U-w&?}u$aCY1$obLR&pJv`$FhW=GBFHFN8zx!*`UoN{jTdrLAW%S`((<-&3vM zAEUu4yX%!4|5EU*M{HZd>?$N)_0!>U(4#6DDH43<6YfFxs$`t%S@ZJH(hY%X1djUx z!ER(6iTetB+{ny|GpCiOEXRxb{q41gzkEmzaVHlB==UDxdykMI`Z2+C4$H2y$ipD= zR4;!yK>9_H*{9_`DpeB?(tew~teWbC6G>eJJ)5aslZ=HB(Ofl`yz-Qb5|7_LNVpS7`+j-2*OX zs_GKY9`e7LD*Q$uubbR=qpF-h_H~8$Jt|LlovEroQo918T_Ge_l?6jKs}_?QUF5>e zl+HD_6y5XArRaohs%-TSF<*<|(E*je{A`;ll#q`dW#6AvwgM@Lf`$83HAr3*bj(p* zhx$8ICeklbKDL8$jqSj({v9axS2(jvWwbsY@fEK-qxQ)EZdR!Ua@0U2*C5LcoTkrS zm60@VCl~Bhl^2L#TaLAAE4yc@;svrUOis?Gk{7q(yoa{olGFC977|Ts*+r)F3PU(H zKSV~!=+0rS^(X#kK-j9w^Vxqv*6I9Nn`?F^6AZ$qCgm^0ATZdyAmZpO+dNkND-g%ZVDnTpo@{XBeBV@}s{d3~8$9*u8LFECn^sHpBc9}cQpJjxyV1f|`N~IC zO+oErh14DoRDO(_%qW6&dbL04R0LN(sd|&Y{)NjQRomeDXH~NL+_x`9Abe7-CpErt zvQJ+r87l{yzRJ_Ts$^W1&(Qb1s+!#GUzG<@Z!5$(sEt#`V)bJ3^&_8m!ndRK~KlltH!7k1iVB<}g#Idld>y`$tq^>E$E!_#uBhU%sQ z*?bD71*jA4tDpLUd;T@~`N!y1*0J&_ux_MIwO@3Sf|upzuV>)old!IlI)!{W0k1o# zy&$ZyI+^r10jKHl=5a7IQLm_{!ro5|XVc`)i_bLb1!tnB>!c}#)N2f?SMdanKW zgA{x?KVN3xfd}DGOH}vX0SZPdIQY^5h-sxxBdrg>y;f>(;&uRp5OpP@JpfK2>hVO% z0b_{z9@!_$!$Q?p@p15d(4vhxkqq1ihuWw;8nxbs`~sGpWnRHYuJX*z`u%6|TBN20 zfqscF<{_d!N7(Iy3Snv|`;Xbm%-vK$ojDttgsB6`?raznruHBUvtcokwV7lgL-Qh- z0DM}P3g}}&;CwCspAn~sHWmah#*MP!d6+t!yuwlzuJ$D-v!GYFx{AlPER>)38ehLb z?TdN%aUKh@VAo`|ljArfipYC|--#m;=NFd+x#8;Cq<$8>4p+yJ`@hJcZPobXM622I z`gZEk0@3f0^%3gR0%^AkZnak@*`MB7CPw6)G)5{zVh8mYQhz56l+9$p4pT% zebvv%j1e#_PF+`@@t{QO;GqxXt#RrB0;#l8E*Gz^p&~Ccpy5Duf0C8~83WZ`WJm_& z3{(##Uzf?%2C4C0>~rZ$QB=UPllhDER-KHSFXnI4<6RWpbxH0pSY4>H{cX{gBEGIy z7D1(Wgd%K%2-*BY75~jO0I2fA;9G@C{`)DzcMLGaor!7AY=q4#Xb`Z8=-DX zMwwvm2wc!E7Ba?xrnRTR)VQSy9*s~xB7M@~_(*jfQYT%0H&UI155+Bj@uSr#_Pz_0 zKu49aMmjG5ag5sNXiTG7^vXHXn4V8l4N(bcuyu^uWM43!&X{AVUU%k0*jTJbo#w-p zv1%96Xg)k2s}3MV^T1;qj-SngX5-Ys-dpCO8MvDc!WGf)KaLC~3NbD_&kLJw&OBH( zPF=f7HwrFxB8^PNiNW*W@i?_J@ty}?#;H5Cxi%ML$e4YZmv`L>97YCY=h3pxBU&k6 zKXC+G6@!r`iNbKnTriDSJNr$s5U{wRU;Ocf$0Y89sEE9m*7R1*T(~q|-Hm)om8(xs z_s7lJ9GE{*y*K=6ilQ)1=k-pBn)4QfvZx_+QFuV^wxIZ;W~RW*N$OzIKLw6V!hj4( zfd`Y+PE~v@WQ;ZSg~GZ*3fN(_v;SwdBAfI1V>Sd$RyS+$69s=4koas$iRo#Uc`P6) zVKkDwcUPOc`Uv6kxSF7L3TR{@pd2ud>5?n$ z)y0BZPd!SDLlBk_6@CXcRo#H(Cqc)lxbnM`V9Zop`Q=F^I&!NN9TSsa!&G%8+aHjC z$5P)U$U_z$wdjmIe9?jkmJEso*DVNi3J(=U z;6V!lP2!QD7_?y~Bu-NsY`RkdlO}p5l~74X6HHlwdNbk8G&H8Ng$3hH-KOyVmIz+c z)lTGDA~c(>u0?VZVaRms7a56+7p$GGF5hHgVu{KYs}!YsT2RQC2Zh2oBoQ7^#=eR0 zak@GpEr+zOra)ZmHS$opErj>F_>L9YW00pvg=ux<5{%Tn=ARO6)2+ z3^>f>(HE#pZu6(f%V($$(OCKUeDy+=`-ouN+33@o<6U^%_Ez7rr({piIAM>xJY5|tkbn{L3zND7A%6^& zgBGhd2%c?z_)^r~c=$Ko^W7TZFv_^*E*+vq)qj9bOVl}J#1P0@svbgAL*y!wTAM%) z9tEHB8gH9@^=+vWJ2rsm@|qaZVIOQNula{`$(C2yYP?mX-d_2bUXx9H(`qupTD5Gg z%#PLY>4wz1lUzb`I-M%YfrF;pGE(3r|FccwqakgoLY18wZ{l864%w-x?L+ny%A>Dp zZV3cF$nCCc9tcE!FZR3Nclq9K@jo1 z&MzNiZz9GtB83_9M>m-*YHuTFH`%nX3|5U|+-aeuSUKM$<(@?y>sB5yALGk{g zra3#E#c$Z^g4rmI->}uR;<)X!X5dpvOX;Mv95&KSV53=QIc^fi-NumynNC?M-)bc~ zR3d*(l3&J(S3F4nR5&t0JjdIj7(%+tf%6l^IPyLPYE2TillCc4d5TyKK1>oFh(ijL zpDYe1+h)U*$>LgKJ)0t%l1sB7W{OyyY@H=1OcBvjr<0(^RB;N4N`k9X#Yj>#Q}&o9 zMhRq3qC9%Kh`0F0&5(D_5El~icq#-Zi6=>wsj>LH}U6tJ5unu*V3_&i%|LH?Ko zK`CM&**OWurHG!yI0-K96rJJc6w#f;PJ#;**kBU8N)g+rUrzi~1Xq6+T_9?X*oLG} zgr#%DJ7muU7@aD1BRwX-qI04neK`4ks@T#-nDB`f!O!Di*G{o2xi_A(?lo8JNG6Vl zpXQ2R$>edceV*t+x{iZ$^TbBPW1L(xPmC4Z&X4&-U;JRjIzQBSqP6kxyyQRVj##sM zj65by#EaUAqv59oq8Eu74VM;(fz_Nxe=2HgoRduH!UELG;aMUNHU7}sMRRgX+&>&kAg2oaTA$25;D`p#-!ayxRs9ZPa~Lh znkOSZ6@`M=MbQ;{n#8TdZ3GAl#doCEaCpBEJ^FGOG+ZS5k`u$^-iyS)@h#;ap@UCLrf%T1L55&(H9P9hzZ0z01T@zes&Ikam&RS zq}~8{vs_$FmiC8q5JPOE`+q75qtDSaZrfkJ4I2=s+{tHsWwO<%aXTI@ys>;r*o#Koj*9~id{SH5K*c(g_gAU1u#ajn?dZC~#a zOQ~sL0qJZ}a5Yx-2KVh4`dinE&Lplk11sm3hmF#}#h4Hb>CmC}OE$G<`POTH8NV#56X}wsV-0lf&*NY9vmYy(my_id$ z_TZs;u?G#!YA`VqV=k=+56lrgcwk=06z!Zsd!Sdai-fZ62<{Z}QG?n&K(|Zu0*4La zOc!H!YE-roW!V;kCU%FPHi&^9%@N(&xFeYcU%-yVG!{888iVfLmv0mU91FV9r7o~; zt+2r;xY-R18^xuhbvLf5e>bYB4>)ZSUEN=F<$+Ck(!i!nk=w5bM&1x=!i??ov#5p9 zo5U*il0wbXC3sF(ShY!9@A9+@WpY^2`>;jti(R1eW--u3V(4t9cUVBSMaGOSuyM24 z)G-v%->F=;3%uPdrjyKArm~O*F`1$xM4QBNX+wmb&r zZ^MNi6axphi5-ZO0=J5xVbzSBjOG!wGaANi7X$4kMwgDLA<;CVRym*VMAwSDB%s(M z*_~kck7ARmGZ2eUGj*Y>#8$J|DFZseVWe=YMJe#XuJ4OZq^YsK6X<^ucaeS_;n+`T zP@9f?J&SPQuIl(d*Yjmm+4ZdE`7=VkXI@g#@X@a&KZ|uq-zdoYS?uXT81;W5^F<_$ zOizg2Av!t#68WF-#7J5b3A1;IO&kXy_PbS%iG)i##QC0QI{YtH*oF@o{MZ2|?ZovN z+kxj)=MFTdyhyzc@P-zD`wldNmU~QXPq~y0LUs{Gv!hRYIKB%@ZuR!?X%|k?wg;!( zVnfI45&zLDHv-~zizzP65!F`7wlF2#kdsdYeBLbv)q8IEUrN*MIF)x1v6xP?AKj-VWyP z#TL+`9h}~a#y4&U1$)JMMBNTte-WeH_O+$j@WTInIc%$x!(V7QY^#*Rws7kgF~F`O z&MPU0>bA0L7TpBB4})6SVl8qu47z1w?_3(j)tDXzdkgr{IE=tH z`!S}EwT6ECMHjNUHB8%&ei+jlcJIeF^fnag%Gg>jheEWB@RisvX%f#4g?>jwcQ`2H zWJ4&dJ0e!Ld4bQ-I{JrVZ#Hcc{mIu5>MJ*Bm4jKlDFmkH;6@}Rgevb22XaIw5*Y&5 za>Q!HF9bg1h{1LRtx9|6ZY!GFUNGo@c%R&D32hFFUN$)`aiP-&`BZ{_*(hU9ORmqT zmef%}B%mc##YK(x!&`#&A#~~UU}$tm{DI60hP8)KR^MRiijls)pq7Wj>36X<(fY_6Wu1eapN4zUvKIWD#)wVJ^D<6<9j zu`%yU`x?_a<^``#p@siW!JZSGhdYk^6XM$neHw9*w0{~;L%-uhvZ`WV35T>W(BQ*%s0jd<)3_-*+K{KdrF9_c=Y}xhw77`4 zHk8$8#56({)nlq@66zK2%ubvWE0OSe@Y^}jK)%$Kz0c!IM2>sv{HKnrtpl?zh^eG< z9d2GxZSc4#25L{&W(x~r7vX*};iC9heZn90Z7@}IfU%dv7bLHi-1oBh5TAVagO>SX zEHV1YQod+cj`XY`Z@DA35{a`l{P9S z!A73{huBTWj9UZI{j~mYyN}kM1gwDM2QN&VIEnv&YDrkeOeP@J}k z{kc_TXb-M}L2=p;lCTQ4#%Z^c%PXk{5%wu7%aBc62|xAIHYUL<;c-7?>An)BN7-Ll zQHCma1s7~u0ZZbMYV-;!xQ%_yvSj!+tGd6oIk^uI+F$EM4gw77k21$V8E)~w{ay#) zU4P_O0l;nmayz%Y4B5fuFlYdBOI!{c1|V77a>yNky6MZ3SuN+TzLWtm1CeZ328%LBEIh-(I@2Wg|og=KQ=AZ=}dtd(HaU~OyCQ<6^&)@EqQ@jK9Gl(sfm zW`qT!v>x^ojD>hhdCpm@KpHi=K}I+@O6wLLu7ER>5R7+r#7&g0@1o7KsYu z4hkxhGj6c}o{ZMkwYNoZN8_AasycqL^DPa$#%P`FpQUj*ne>GzlkP?uM2yk8wcBq2 zD;C+6ShQL}Swz#@Vv6Ww%PcN>TpH{ggEqBFgNI|Z9>hIu`B?4ET5ac-(IgOu)Th)^ zegjguhvq(i`8e%S5;qTW$D!%1=E1{pl*_#3PS$=RWcY0GP0#m%M? z>NNf`*KS=nj?>b8=o7R?gBk%r9N@_Sl)|3^B7M|GgDsA{_{h^}u)~oPAB7kVm2jlv zqj;mi8AmEQN@o|V#w0^kgnZag&Pu<(ouJ4^WF{KI#Xdn?n9(^*zuWCPo+6GubZ<0J z4bD?Qq>nY%AeWDPxCZk)k9$65F1BLipMosWic)=_lCpMN$o+d?>i-9X#lP8DXODgqzX=Bj+mWVlGK$}2t^$yIrZBW~sWOz4}6 zMxI6pa7*mjwA4_6EkWo72UW8WzogQ*%*z%z8E5hIKTYtSV<%w4SjK;tc=cqaK{$3qDFfhREhI9WC>rw>yo| zRnZ770`n1Qv1J+iO*Uf!>KS|%;YKvT7;kNK+>HbM?$)Sr;~()9t*X8Sk9d*X!kB>2 z;Prge$C!Y21ZVKk3}b>~M>+x!K5M<)c%Js9H96E2yccVa5LHunvRE5b?f4GNX!>Kk zG^0=90Dq1_Uo+b$1mhn;ja%=KTP)G0nFgrgaK!gjD$KF@1a&-%l+>$0Lt=448VG0kNen#i<^aU*3dUs`i2l)@r4HgIt^cjv&kH zU=5JDAegZ*LL39Uy+ZBAHLjxXm$<&=8;%8Qdyd1zBE zn&^SbzH8>-=)y5n8e;MhHXGGyC|QwK5NmUzB`%{Zlj0gnvjl#Nk9hpXCV<;)$v(Jw4! zSy{uPt6Fy$c~*N|)e^A{&S@9wzM+4VbtcQ<;yG=V=Kmnb64jsBIge^eszf#6PNq?< zWv5Xzs%@7;we#BAz7-rfq%T=z^2E<9cx1Q;r+Tald;*%?lXN281edqP(I11+9lu z3r<*8PM|lu`&C=1MFWnc5|j|G#~`Ux3WmDn4Z@n7j!IJk+SeOGZ)gWY;C2%_ z%}=+N9%`o2Zi+d|zlGE6Kp<18CVPY55`=!bO(s}1YN;-p0I!wBZdAE6Cak%}6rxugH z%e!@mDwTKZ*^uQOov-8_ov-BGE)J!6m$gv-a+&su28E2hl6L`x@N+))3b#VInvcE0 zwh;E7!Cs+4DjI5KlI-7)6qs5z$v!clsce$H{|N1`Vy_7KC@;LKH43^-+%X}j$@X-f zPOF(?_&dYv**Q-qN~)yOc6Q2|#7+*S>GVrF%($+t-7vd+apWGrQ}h`#swA_r5URKf ztB?+#q`rgmbjw|f=dE_-nKd6l|H-Tr2DD^WDkq_FkG$q_oRV2-97kgvaYk22`4uzk zHU8GKl39Pd@XUIGp#R9Z@4_?d7DtxKtQ!pSeP&(Zbfq%uk_*kO#DI?Ydq}82cY5GS zg@vdmAJJT}ggnnHq>P#a?`~*=bq`XC!|!PdPpIDzgh`Xj6XGr#r78&(yp`b|aa=1p zDw9wQUnZfNZ>0$p0WWW2Gn@8TaaQ4fm4GUyA$Qiy7UM}tR`C~6(<$t`W;UOyQ<78% z=r2B%B-O#$aPk%=RoB#Ft9s!nO)Ad9-yK9}`o-Lu#5`8Q0e%df%n4kp!+*ARLKlPVjj=;|X?N$1+lfT=+YXz5%( zaY_RNS~}O3*Rb*qCe^!FaQ_Z&z;?Zc+`HOEx>4v1CCvs0E^Q#h37){GSR;w%W+C#b+v~B_c5_@?25%5v4eN_v1RQ* z(0}A?LnLik8#uC5Vy$P8?-Oe!rz@3MV8>h5y$9H`obmNi^obWeeBZLFB9M8Yq-F6~ zaF`DM53yx!pH{p`JEy_8huE?U!?biyT->s3_-46O%VPL48Kzkazdh9U zcWQ_~Hbpf#lezhqMNJ{gO=35UlmifSeS%V0RqhuXLduIS7avcm^q45r*>4vh>;M$%>55kpWY0bD%Q?+G#?j;18>%?c76o z;g37egPpE90+C-K2U;T~#6Hzl30O$semdZ2Dh{V|?wX|xXc5V{`{_(mV8c_bLsHIU zrjNq@ARCotUyzCKuA|=Z^fhC&j4M0sgYL~ zPH9G<7b@M2(-g89njRc!%}8~#kFyp40#1whi1-vS^fC6hbtSIg7`&8RgN=ooIA%U zmoA=@p~7=*qoiq*nDokk4d5{AoqzlVnb!NSe)YiljLlr%0O1af+n* z95k}lo4_u3}Z%*9+l=6j2o&bX!FX0AaPT`UBkUdqJ>yoZm^wM~<1 zQzUM?8BHpkR7|6(UuGgN>^gr=8N?~$@qoN(fiC#W>xiq0_7VKWJZ5oK9C5!FB7iI8 zj4+&JO>a`5v;;h&3JwgK>dbCk?0n0nYbtP3KTcxDNrKo&Q<38g99KzY4PRbpYmJ=3 z8(=c)c&Susu?)?02IP{{6dAh7oRSJghbC|mMdCD$QzXvdI7K3MT3GT@`$vt8ku=hx z-l7q!@RXWcGo12TgCl*-C_6-K7zt}%Y3n4lrXW9E2Zmup(IrG(In)#9)Q?OXRfvBf z1yi{v_{9Z2b&IoiE>u=Id=2;L4g}!tU`J%yNS{a~;N$Sable3I7wJhK{D6qp+6es} zOc|U=6}8jde+(O5YkiW=AP_xeRgSHwGd=j}u05iRQ~lUT^D7@2_~;KdG6iwUvm7^+ z<6NK8d8Qs5_m!o6>U@rK=ePupvtpyv?GW}xn^DihM8pwIBZ=^Rc#?>+su_ZSZ^@ zy2(z{v;#hUx?j_}1EjyxrVyPL?ElhEN}7njB^jZ*%zEGOq0BO+_l?9+gz*}>miN9B z7%f8)hCZXc&ycoH>3stkko7(UI@1bmr&)+U9f_l|y)O-cw2YSOeVV_uRg&&eIQ|w6 zM^kad+%=CF&?1s?$KTT7l(#u06Jn1>CnWuFjX6hYki&4qV}LhE>YKp`L*LK_iEdCDWIO}128lqWLH6d9N`vgnNt6cJ zkK>dE*`MREK|cF{4f57izy|3dSN^E=B|b?*m`X~QoP{H1r3c<6(HNymK43sgmwd!Y6iH7w zPU(`*I8KrD2gfOr%p5nAYN&Kc{3T~xcMa}ON_R=C-z{c3v!+Bn|MeO3JnfRGm(nFa zJ_GoST{4{_{d5_OhIPqe8qMM|6ML{~tuu1UAkM9Hmn`I6avBzxk}f#|N8InUUva-D zAPmj0#0fe-$I`d_tw*7&CnwU_nC&v;6W zm^PCqZeC?tYa-Zp+a+A+u*S?#xlkXW(L4RX?zLj!bGRb&ZiwSSR%U0fzDiyc$!7^zFdf3H#`o(@3d0?`1P8V zQ)U(8R!ZEjiK!YFcopQ92+y%%axF}-?;$;h=f8VMPdMy9dq`Hm{;`Ktg_C^RL#isU z{F*b#8g%HbjV5TMN`v;rVs*|geG@?-U~>A0ih%{;T|uA@{rsuHNs=v>M| z>$1;adKH+?r7W(UwI7Bkf|3i{xQvo5C2cn0v5Z!%^GRIfFWqI%*)%{aEz+Gw>Fpaj zmlNo{R`LkXRx3noDVQjkNO^i_@#9F- z_K;`tzxzwYD%8x=1|2`+`&-aW=8&A2dh#zoz3RXf47{b1NiSP zC$%dE=q7Zgvyv31lS&8zbh^&uDogI2992f<<9t^rK&KUK?VGwoC-6kfb{RgLhyJyx ztK$E)jK#Bc|O8IVu++_H?_|P zP^#)JraVCsAaJJyuBjT*IxEjM(PQiJtM&aXU|AOf%`{B3dcYrU#yo7X;Nle)XEtvwvtj25`ADl z0HSVE07C(C0YC=vohZ-sR27(>FMv(?A}~OkEGVslWRf6xqlUCo1Wr;Zb<+gST~|@9 zoB%+r@k~9`ezDJT(^YE2QdYH7b7tSyS%Z*0XQhfc0mgF%0M8lMdINMzRbYvg#46Rt3#3&<|56R5zfnWl1p+6D7z^`hmYWoq^5UAB)3@Bgg8!dfwSTF= zlB9MErq2aszF_)Nkk}LaQ{e0gz7{xpf^P)QohJ`L3#afGM+d4?S-MhR-%2g@Mj=34 z5#psTJ!^CU05asbKv!r*b={@rwKhkoIsbt>rKG#mPzmXe2vGxfsaj}ZC$)jJ#e;ZC zs;d7HUbS*#;zZ4U0024%)a>N<=t3U{(H(awK_6oIhqB$+LdGhRZ%TClQT=zg#*N8I zYzfuf#~GwcSRiA_)f1rr5sFkpW_LBDt08bkflJ!Yy3tYUw^%6MT z1yV(tSbxDDQEdXZ5Ft@*K4M&(0YJ6kyKX*+7VV)$Ri#k>01ge%HBgc1cG8f4k%sP} z!m83E*XA`KxNxZ@q!ujabh_$v*F*Z9S;8r&nv_=Q?oM6@$;XjKq$=2Sw|7#1PiaVO z$4ZhzI~bshbCVnb+$Dzx`1w|r9QfI_gNNi$9fnvB@GIvfITYZx*jsXN!}|;`@QbMa zUme|L*55)$m(k@-+V6HyBQL3Lr?t)1rVK`5zJ`~7xSh^Fv5pCOjcZrY0Bbmb=?Wh# z0K?QLSj_%k0S;RJ$u)pYInYIWG@N#ONmbcT;dIVRN=T{P!pQ-TnnZ$oHF!}CV>zKn z0zC+OpnG?#9a38!czYrMHWl-klL}N5K~`izVpSvP$_bpXmDB13P7?9-0%zIm&DHh! z+dd_Y%gMJ+>XLV_LBJwMxsXrM=GKwim`U{VUMj+z4+PiW#oW|gP;+U< z^>;zpNlNdG^u$1EicuT7pmMvIV;r+tCP-wLU zK=Jhrg6@cX;~@R)C)LuOz)Wh-PR?n1M#|eCqZ}I zC`4&<;P~Vzx>t*k6}6 zVEba-xBtMqw#Np>y61u>SkRm^X7ur+{k5d7DFeSnEEnAf?zpCZ%hgjC?I<;5-p@k; zx|#MKu7(~}*SsQBpet@9n-$53SY_SZiE$KDRYb(lXDtxLO zTY+ZQk&dvaAc_c-k}FN!h*UEA?nZUO$4fnVqvcefgv-7DTtjt&q|q#G4XqB6MzH)f zma_Gv>WuAOWvLx3)xa~mMC}_$djtCsESpi8c=bsiotdHSfUx~l25e}gMnoX&kfh7e zHXsUWD9v@9a)x~(NR3#x!g8{qga>1jQp>*JLX(mfwV+k9CXT&Qk zUBw)-Kc+0_%eCykt{OgHMehe=R-L=b;yy(3(6H?*DKt^K!?qDs9xCl;I-*NMrEFGn zg=OV1X`my^T55SWQhK3bk&Efs7g8uIUPS(*rF6D*5#3CYn$qv1B^Q1CA_kH4$IC>0 zQ-{#-MdUa}nxwzHPzAo_z=*vIDPxS3r0*zzk2x@?;X*1u7IplqnegzgAKPfA^<$-e ztdp5Ojzyh&nyLCYXHV^o$=BzcF<&5 zHeTxM=-h5T!^^PO)$i^)&bQc-r863r33F9$WA3Wpbs+C) zsNCQVv~wCNcQI~hoi43puj4G%>AWNOrck*QDU9XMq&6wiayD=#uZcGL+B4Piib^Oy zlN!!KC44hO1&T_TJA?MmLM8YJpr{1L85BNS8pAeCr|)M=HQ9*iyb=P*HXF6=KAjrR zk$l2AzGME-_K>oyI3c2V=M{ zBZ9gwkVdiA<0)%_6w4e2kh58;#cG|RCT3|DOB_vBv($(=^e3-{Qh0?!{bYyq(}(z| z(MM;^*Y4;?BNw7B$M&PG3njmrU4X|6zI;q2<0E2SFCKoNhLa{VJYIym`VG&T(es5; zXxQIf9T_B(H{FK0k3D_IJmY2Y~l`?sqG}D-F^G}+BRFaa6ss1u@0-n0Jy?Jg= z*$k&g@JyKuotu(*iBwg8lOwL2HHKUNPlU&27^?x_~&g+k>X5V-*}j(sWJ69p25&M^RP)flsg&Pd{_-}%1HQsL)0AY zPk?a7Ioj{x<2@-yyU*?uUw(`{&da~E7rA^Tx%uvE%o)X%@hL%SP@+{OKoB0mN%vP$ zbjmI;v5w~rg7gBA-U?o9*j=5;BAaQS6YxvJ}i@ESkFbx|XK*#NhSQoqh!U-7-2^olJ+!v9J@opt<4Hc~Xg~30HtQyEych5}+Dbj?*>WkmTvdRg zY?o}>OMNI}g;bwy>_ekhNM4m@p~0*jU)yYvU%r`-=1h$kg17rtNN%h{58A&%im(43 z6_?@^a=h?4@?vgf!@H7`Vo;$^(3$xdQScg2Ft5U*N;ZRj2(`pTwlRf={z~8gdjuXt1@YaK%vKdwkru`)OvnIm`RsdC5*TM9T zq$ez5D9v6kRbH`5a;h21D@42%tB(D1#?*oQ+fi*@6%oa+MsyuYL8}n|W}+I82Jna< zcuoDUh<~aGHRAO|GOv<6H7>McmE;ZQ>?%wr&+5xuvBXL#M|-P2m01l*IHNv|T`e_p zON^HtqEd4;(HYv_@D@2mo3vfx>G*2NgN5S4o7GZ%_cB1}4?e6kVRVi*x1QjYqdifN z{MJap@yh^7&6RSrsqjEyb;!`phA--MmQPZ})Lfq&?Fa;+o&hloKK^c1Q~u1?D2%n# zlP*#H`uF47Ovv#tZKV-NY5DQ2RDblJ@7G8j*ulQ^evRbLzU@nHYo(TKOke7`R_emq z^`#waC2yV5m-io>uGtKK_n~WR(I4~blJh#LTHTj@fHK9n8#7|?e&}xq;oijt+@CA_ zc<54uclV(l>!2OCuPd@=H2$53f!CM^(MWx9vzu;QcLZ$y;}P}TIfMryTxbm7qenXg z{wz%40oK58FvX`zWvmZve8@@6KJ3ie%%PkHI&;xmwc;)2z=dAygf zltYs7Rjk?YL`M}iNWPkK)EG{=Z|cYn$zDkPaaS6=LF&w?D_J&3HJ!bIz&M%0af7;2 z(FQ4oRqIL(H%bkHrgY==(hg5$VoHld1?KlwXZl<&3XpXdqlq2lY=#F3 zG<=iP&nrEFzjbz;XSI^i#LJ*&HP)1CGYn6l2b-|5Idc&OeS@TL_M?PvqzSB3Kf3UZ zggbHiQQy5!lhC*y$>EVMmt2b8Qjm0j20f6+Ko&UL~--O0k_(Y!`u@Ca~Q~ zvCUL$BZ2KJupLUVek#^YU|V|2NZ)KQmZF_i^qUT9iK~mqZA-Cl+Va{e5LicnjV{IB zQ?Z8y_JNmLA1z9;=Tz)^fz1)vrbBu8F#_&k-EwBeuRBb@p8aSk2Gt3d_9Rj_lG;$p^@?e2A3+%p9 zY$X-jMqtMX?Cw(RM;-}S+e0n!{8H>z6}wwtuXAjMb~Rv7CxkL}&PY{uO5UD*K9jL0UWgvJ8dU8~&*MyQ zv4lv1Tqtf&-FHGFoo`1|c1lrfX?r@nQ}P@-2wX#s7j5UWB}6#{(${T}K#2BnRoNk_ z92ex6J=>$1ZH9SmnZtfA@a*DU(8ux&LCn-L+H#SxW(e90&3R@`x*(3jn>3$M5f-r!n_$WggLPjMA3x4zPTZZ3e{Py6NhTmcQR^pe3-*NmFCl*ypbY8q;InqE%CK}va#mFbqv^cO za3GzYW=YLic&H`tq~xsepOD5Ix&S+aQ&e9uY{`ye6LK0t*fPX+wr*A$^~;t5DxYc$ zQge4`K{KrCG|>0C%}^zj)@4h4TYDhPpO>$MhVKweF1b=n6*pjQ$$Wvd z7FB99Bos z(A!+8My-xO+mg#*^aR=rjw-VVfbdFgfjcOnkiD@P-UUvV>6rzw#+{( zHFMJBQ`TkdqlVYAgj|u{mSNt0R6k!zVzXHll}6rdv1^^({_hO(ZaJynHoy^7ioxq%WKsX}45p}d`{Lh-jH zzv>%7P~?f^#=v943%ljl;0IOHRs|D>Zgv$~cUx+}I#i*&+gP!_E+p%1X}C)&`WM;@ zMN95zGvEWvfp?^e5uLE1V(p3dQBdOA(YVppY-kSJrsv2oWrbSjdey zbLbcD^y3|=cC(jAmUoQq#?GhzF#+eL-R>=V+K+k9!%bz5MsMv~wc3!y+ z<4oE!RvK%Oy(;-QRB$K?0{z#ZFWL{!N-MRwE45AOgLi}Z1BTjm`~hKnc2yslb>!+g zSm=4T=2J4J%&&OH?EZO30u!vLK+|=MJWs?{H@Cq_7MvP#P6x2c1`qHmUlO_PKN$5$ zQ91pC(M_z!5AbC!7@g*8bF<-PJun*g{~57=F#3om;W6WXT9}y%kgJtoV8WA+hGSr% z-V+3_(*U&AP*?v~OcgHjyg{DqLk$;Uemq*4Hr|u`4WIF-;Gu2IGodmWRgVhpNghg1 zJLw`fvfYzBEBd&hH=DIl+zH2%)7o7Rss4Sby8l%JAXx5TE6l~nM*{c{<8Rle`r?#quXBKp<;xLVV)=8 zPp*FubF)K6#19DY_vD6@P;Taw7X{@?PN_}JwG|~BO+`j?=w}Zk)NW`1oLF;*;F3j# zHSijr7qr7TGqa&KGfQs0NtMt1w2#r6<;?yTZn zf~UIWiB;N;=Vxw<(Ei6#m{a*PuHcpIjKe1RH~R2Gn#ba=S?0c!@X%erua#Ol3#ttt6bL{pNdqMr?ZdSEO)BQI2$V1YANF@f9J&N zZJ^zCaT108xw8)C z1)TQvc@~Ae;1DQjHMsLwBh9@y2s!SYiHWti!A3W`Ducu)+iMcwPm{a8i-?X54@WM2f(&HA!? zwMR8edAi$UT!-3*7-0eA8Z5iBuWDHWgJow&_RR_k50L|FPt4)3!s8U$i2a-550l1Y zU5vp8XzCl5JUANm*m#FjJEjIL3X$Vj?HsxpBJa}4@w`^_s{{*~60*c}%Wsz--)WDL!5{osBY`f$c+Fh@r~~TGj;V zpUx!zrm}DCWtqGd;5*pW3-ob*i$SX`f751$c zb2wNTQv{zFee?mpTE`znXKkIRuNRsI+*HqG4}HKXs{^2Xx=*dePeDAVcv(D~$(b5< zGl%Yk%XQhV9CB_h_wX_<#@BV0O7W@p%HU4*)RU1I&g$G9nHmwELvujGt}dd2=5ke* zbBbQ`@PI|sAws?+?>z+3J4n0rkR_mn{Gt-;swa=Gaxb?-lOd7HU@OEgqp5Y`H00In z`ORc9b(I^k36tqqSJ{hooV@LJSDCRR+bwsy%l99P=ErcdY3;c8X$6&!bH*ZH8~wQ0xA3Z#HoaZR{`O1-ez# zaDd#FZCp(=2gog$&u}_AKn`$gvzia3r06(vOg<)Hb9bxFP-nH}{Q#M1nqScHPMK@H zby=-DTy$+XtAZ|A&k9g&fO74i{Q~3$P&OVqX!g0>RO4J{qvS9HTlQzr6TQ}2W(|_@ zn%skB^y6STu|oQKuBxEf!k3LYjKC?ru1XZ2Qz2p^VGMj{yezLE|m zqPBOfrDut9E7!QC8i&`PHP!HqHmHX&ODSroyukV58t|Pa_+}C3YoO;tQC(%f;><@m zJ8*(J#zA<&UH9h-`fiv!z@_#e$$=%+Ilw!i&2V)wRUIz3bDlH+8vj|oE(!7cYB5b1 zE_bTj0DTLafDMHcBAiBxsbIJ~md$xfaUbVdl+WL=#8JwVYe_{gl^{X3LII@(fL7zl9oyjA<@KF1W5Q zF2g9{1sDwZh17DiJUC^(2~t^~ei%hoSC{j&Ljl2#rAbOZog9mCTDdnL?#H82@3cG+ z39_ib+>p!0D>x|3Lsp|Wb@-ViH)BX<6jpFoa#i(^ADneC^I1jLe*p?zKDAhrtV3ux zLRM~Ox)>X$sZAR@@cm80Z-R6$9BUrzy8yZ_Kxa7U2nU&3OQ}sAlHE>efBBN)$H+0v z=}X!$Mm||>N`^Y&n6B6i6XAu}ft4B@o8j1(lrmQKXxH{nKGoR_y}ncjiMJ8YwlqZ| z9BwoGIUn)4X2qk-GjV1dEe-|$=FIKNK!z?VgC2~PtCw}l!1Q>Id``-hEI#Ap4y^ix zxspTF{xX>AVF$+3`eGhu6uMCD9G17yTTBxVAI{hlPe2 zizp*WZp_l>Qf89eNFEA~P^64=EgzHQS$LQsjb=@ho3I(FbYP+!$--0V-9)(~tB^)< zljN$ko~23-Sg~13Pu@y46|#Xq`I2iI!?c;HWS%5@Hd)PK;(U(pB$#y>09dES@G0tgEOuWqxaYj-%|XR#2x z-2`o!;dz|HO}Z&?tmilg^#DH>G8vwOInW}2yE$EkX95Rp7N9Kxw1R_{0JK{Jg2f0` zviB%#up7o%(NFNc{3BX6LvG?NO~-&lGbW#~*+9>m2t*!&$nOz7o+0;T+L;tP6QVwI z2AOBdIKP-q2WHBi?Db5_pDEW&Sq~GH>O4=P1nEKUQ-KNpLGKxfk} z2O3Ma+iJ?H0z4=ajAlXmZ~KX7Ex}Vge)0_oYmNT>EG{zRjSURQ2xV|?a*)lU-u2Uvx@NHB=#wvcuY|PLcg#)JA3wKqhq(W!A za0hDCeflLsPGn`KQpA^X-4u`CH4g24^Ym$LxsDmGeRp5upieXNfJt`>fjHkYn8u#K z$BijE#f9s3t0a%HLuCv%oK*woVTXkPr`M;=LK7hJDg+Q25f-UnEUy7J%s~JN#)TW= z;WOwL;cIvfA6W{Iy-y#$ls!|%BWp0x%6p}M_zI5@8M>(9`k~Dp@Kh=xeP}Rm+M9CY ze6>3fJI+_P3(iY@pNM%NjlFcYy<=uvMw;I&)JLMeTSNmyM3e<8AU4xl7f&1+MyXtj zbc5mY)h%eyV`@ItI3Z5`h-bgkMw1*eJPd0Xt}u-Q8C+eM>LwJt)F+(5?*vkP4EUXw z`gqR>6&J753L3yvx?GNP6}S(8{f6*a{4OG1PzG|2bnjKA<_qMSb=s;0N%#nK4$yDl zX2G?h7}|yRKng>IV56^g&OKVNKpvA4g{c_UEwF|F<2Odw6GZadD*)@~Rf5jVL*;pB z&O>yBm->f~;>?D3(1GL3o`3o>yvF(P91<`{Dx-u;iTas$jXB3#qUwAzQ8*MZLHF*J zTKK%c+|1&#$kHYJenqS^ZuqCIr$%-0EGu09Td!!bS@sI4hx~%j^Pw6$p%8xmgTl|b zUdQi2Ovq_~d5vU+>z=-(yJmFxmUqc}p&S!3868=ldO~f*9@-HvdAI0+zF2f9adDLC zbWF$%lup|PRJiQ(dUUvFlb1vbv8w3!l8!BuL!+e9D1{N|*@^tG#8fHH4dvj|&;JEYhvBym zG{zCWC-@K?5DP6b-0&WtlzJFv@8F5OQrO=2tUi4kUtO7W&r3nri!o`Vcx*m+F+{h( zuTS&lcBi)Cui+*ob z;qkie0)Gb$Yabu+o&#^w&Bf5~U2oF|?!LH1o=fDauIWe>t&VY!@DTm~R|6TBpygWJ zqOnWlDk)cf<4xmP?Iy3fT+AgW0EpE`A4e%4ahz{%k`4p^9sK&Vzfi2gDeoa|LqJdf zny*Cs-&9gQ7tMjssE`;va%vpSBmD(D0so6Uh}e03VW;%C0G`IU#HbReH{( zA$)cwJyl??KHUpxCmQvmPZT~yyX(Cp(Qbz7oUj}>)(JV@-jt8l{`-c?D-sAX3qAxu z6v$9c<&~#TuTjeDYw+^>)Kzr{cyx7A-36aMEsW3V;Rf~_9bPKCr{n^N8<=C@SP!2? zWpq;WG7Ce8_lx1BvHPpB3k7(p04D{3(|Q#VtZq4;LB;mtxNzNP9K0X_sTC&SA1@vX zQw307GIcsHe?wEzA*mO@uL{({8TBz*=>{c!B{yOd3ux_Ea@DFkfkMq`xtnwtmHGf4 zL^)bOd0)vjyY&!JQ}IdF}Nv*Y)Y&p?ry0w!Jei(PtCyn$-SX+wa@nWJPEM?kzMfPI4fC}KoNbR& z5nn?)H57x;6@(&0=sK!-X}*SbEtd_xkFTL?49P`17Q?0sojnh~Xg?qPhe;%|_{%lw zzC!j-QFvso7);^2Lg88-QJ=ZG;-tr_IE`5emWgh=uO^!!_zmvcY{WCwoz(n+X?Ez6q!?+eF@_nIzZlIm8LZ z&{z5tWWRIKZReEl5{_rzkH3BLUg37#d;nC>m=aHq5)ZFn73HUTinpHyhoBrJ4dy<2 z`be@*jfDti7YDq_eixqw*P312O68n-3eRCsEBhX@4Yyp9R#B6;(ti(>{ki8e%2MMWRHHGfrE(U zdDV7@KU}xrk;uBX2ZGW14g!~efN^%F4b`a9s^QGLjnu$&WEwSd;$-Hugt}S$fB6$I z^nLIPO<5)P4#5GYT}o#c_t3tDngN$f=>sKF8b#6G`=wM$=R72*)v`Bx_>clt%gv)! zmPRS`MANHs_|w$qIUHyqr7xmW{eLNa;3{nayA*e%kX_Wr;KJSFfXCT|Hw>GvqO_UC zGxM@9K}u&|dKR@ z5}t=K@afYML@l1UMDN!^M9v2g)0`HLb$TW$V$4&xp{aN5hAj29{sjX zuIe!wsH8@ialhc6aMZ+Rc+drBkQD-W?CysCge)b23=?6v#*Mfz^NTqk8CK!s=C@_KO)QZcb4tr*W~@cuuk z*`@>^?b#dN|0Oj;07t^p?Udn$8t~Z@{*2>FrDkvQXO($@&ToL!tb2hTZ;BW?{Ty|^Hk4Gz!pPfa(EPGCd z48KdEU(3EJepnVH>cguu&UrCn7gS!D(Sh@K3P?s4A zcL4+<-v6EmW0@Au2|ZgNjJWSqaC|ksO5j0>q=fI~?g#7Mk`a0<6p5Ut+ zeL#L9BF|N0J-m;V%2h-%CKeNE7KlrjGrm+S9=u@Mx7Y6htj2As`;B~pUA}2~{*By2<1`gYu{HT14csPIqybyxQS8kPy0Ar#Vta3p>sGm; zQ#!Oz>*NE1qVHCDS=lR4|Ey})@+9n5-HF87~ zjxf-MZE`tQr+~iShPBU!>vVS;@^kV!Ie#mUXVnU5&bMgBYtS6Bi_whPchQX5ci(yb z!Xa-T@@AY`9`g8ApEHoWWW%fLfGZ}(qY;;GMLyh=EieLunT6*LFL+|5Dv z(TLgi`&@^Rg{DwXdmA|YJOdh$hpzKbm$}!_h}p#no-KKdcMtC)>8o7qLqs3Z9t923 z%|*JN2jM??uXwwsznU&Q`#Bc8|JioAGELkrZwRlb#zfm81D>y;vS6bA)OI%k(5E&- z+o9}Fqmjhf>?LKPHJbgMe6rj$t}zsk$+M2% zLzz3}ik3k;8PopO10`ZDQu$suLAJhM&{h~B$oS2p-E zjou}{VKb{(hV7PHX;?FN%lALZL5?n6JL1UJl%<}q+YEi%P~jfALAMHk+6;BusAsH| ztsBYSdRKI@p#+aSd%r*^thdA!N&pG3P{SZx*|75iJ;m0b3VY}XLo-z&~Zl3Z$K>uN$at$27&u*UL+KO}*xpuP^9Qwb^Q_L0q zpLt5#R-9Itr;M(^%~NWXivgKxmD0QdZL-L14R_yPCo$t?%l)!jttIH7s`*PA zJV+%Sj@2EC2+v}PwP2^#^l`r&R55|mmPRNtX`D zjSb7u#X&U}j%v#S(mB6UwS$mAhE^1IQ0{67<~XP;oUR)DAo2W_zCMUMt(HY0$h#1F z$NZKWhksbdXm~6rYdqFdD65F|434!5R`mZdv+3{;F1^5|bibOL>zqcU1DG>7pS^<5 zKF;S7#5*-PB| z>K&F{Lz7i%ZrL*uz5{xZcu)AP-|-v4(0Dr274`V?9x`9#W-~l)K}m<@P(yDJsfImm zOL-W7p`(Xok8%?@De}3axn{+EsS>?8ESEP1@C0y~3NKwH9>r`hz_D82@IwCEw5b{x zz`$-GR4W|T<9}&8DlI7Pi0s$wPt0nj7hrWC9|OB-9#`#$y#<#(SLx*u^urH$>*y%@q1>GJLl4?`R4x~E z9kV2iW|7!M_zt*$W>jlw(ndhRnDHe4a^V_20r zNAN}nZ&({(V5lOOpm|Vy30~E{yyj~D_6<12} z3V0qpIVO9g3`9^JiQNReI~=R^FIc(ZD;@YtqO}+34jg@2pnGvNR%D!O8-f0eqrVgA zvmA}{1dg@{^nQ*u3H0wAT`oo7^9249$Bz>D4;+uvQXaifpdWK|dx3t<(e@5_PoVE} zbUlIYhy_4N_X&p|C2kJKsu$=^99;>_+k!hs03X5e&;L|Q9?S8(e*hgS(2Y6zl0diR zXnTutIAS-sL>)6_w~o7@7azbT3Xi!4exTOEvCczGG*YruVr^|R9Bu}*YPOj47`45H z$HW&gJmwM+bLmCelPUWIP3Dw%>x&;PzQ+x;ICo#(oS#3c$Jpv2B-p~(*sL?-o!k?0 zUB6wNj2mL$7y`^AIdhy3e@Lttm&_KFMY#%7AzdI zkl!#`dIE+ErZCDnAvg4Y)C@`d$IdRR33B?$&TeoxRn3x{I8SSg1KrWaLGK`%CpD)2 zS+YlDFTh~eR&0%0V#7yinc|JQB zO3^3f=5n=`u#xE)VQ5JiCuKjECXLnOaTubXM+@9-Mn_J{W7ybcR4-fZ;@(H)iO+Y9 zIF>BdOvI;AFjMLfN-MK*YF)MwsMEH;d~pOOdbCPb(zNyufJVOAqLbxMB5avRdV z99S*PYH0bGBlm@6OfdC54LgUO!IoL4Wtd_2a-yqem^&Gr`O);TmAo+g z0UB5#>MoU~zGvkP%w?tJ<5^kOlsm$!sWMIm*V?GUdAS*j#Iv#IVek}Sqr~%aJ!xfK z%wxKjA8GA*EI!YFq|Ecszjl12`{(5VHv1##F32?laUO|O`ruFsCKixr{j<0^z^gzs z>iX3-Td7FW1%IS|7ckkoe59Ed!06cr+IRtsPJW;>7vvU_AEKCaGe3~aMcL0?LMQ}v z53>!-wBb*X7PBqcDS^XAg&C%;OE#U5$l*0 zml5+vT!y80fxM5gvrnkvO}T~q?isG+Hit&nu=KhqdusGUiufHo#?;dqW0=mzpXT0z zS=&=T%Dg4JNjLqV^=fTZ>Gm!8hCx9HW~4<=_@x*yP(rdcU%Gf(-pV#SrAc>WKUUqB z*4>etM$UZY(ML-_C> zWri-J$YQuFPt>pm)yaHM9>Kc*M8)@Hf7b9P^0_Y`X2X88+`5l5dUhA5!w+N&o4?bt z@1Z{FaJ~Gh zHcS3fdA)`u7FZ_#A@9|&ly9j13z(Jo-=J|X zwZ6YWRbRqPqnWE^*-N>P#^sJ48gX@#HXm+=?y`R0pK^|-QcxLnGO5b#y=4e)n6hc< z#$WPhy339lhrjbZj{lvXdfbuj>~S(s^lSOD<0&Rts{AdF(XeipEMLBn=W0@t`l$zY z+EJS|4wDj!I$=@o#E(k*06qz~A-HI}08`Yo1Rf3e#2OsljKgb{!0U3j!r@gpT+e+j z@acPMV?B5hu1=}1Lm{Jk;JlW(@Mj67KUely9$}!gFFH2Lc@}-82e`PsYR*BZIWq;%DN5#vn&np;J z-+&zSvL?6V6FC-f&tFgrNr}}P-Z?o;=p^j&*Wr2#v7gnY^?KCI6xYNJE)L(3~2 zy^cOp4Gt^tlLF0WWx}(@>y6=mjbBqF!5Hf)T`jNRd+Wm@V*E=U(d6~b)BhP~K9AG# z3H_l{y0X=WDB2l`HGM&e&dMfMw}=!yG7f?)AX1-aps^~PwBX;@?&{N94(^8Wt-v0N0u2C z6dw(<714%@N)@(jKOL;7JFcE zUKj@j)xTreP(_K-u*1Jw?p0OXHEh#;dhdbWb>|)(t){GC^S`Gao~Wn^H)w|^Dx~ub zI`4_^<5F*uhnLcXohh(%^HSn9hUfQ@H&{ykqlRwY<~3AU=WT(SDZR}w`8r=DSl2bQ z*^01IiS{!Zx$cpRg%k33<`!M`QF^fPx2SG)yPl{0;=h+>|pJ#Sg!ah zaT@2o`1r(>hX$!&Gia_*P%ULcmAo6c87Xx&SHetxa|x?9aL|EkmIt+zvYHA%7I6G8 zSc1ly&cRCL>t8J&0+a*|Yx9dGzK$|X!+yI$Cj!y8cU+{RK&4*!ukaND((tw!7>F-qhsw7jlzl*L}A?m+=OQY@jq|0bkIF1|V?#g3R1~J&JZWP&TvqIn<+}@{K+<2l*fL9Lb`hYvzy? zqBJhw0zd)z{S>tgQQDOE!-=OT{?b#lHbeyzzG(HUN=W@n! zCQQk9WX%@P<_P5=8-0WZw7}HR{0M#7LK(-dAEpm2lqoFnBu#FqY-d?nbnogm2$M-l!6TaV{@i*>bv*J_@Eym zFGrhxg1(4SCa}20bT3Nj@4054efCP{cVw$yw!jp@6kEn-Fz&bXYo%Bjd$@p%F&O#< z3u#)6(#Egdd?$y(#$1I`Ke2&vVUnM_xB$U~39uN~Xe^`$F-m*()zcWIARFEvMtoSv!bq<09GB-%N8G#j=ov-wXNoh+oxZ%{7g$eQ#N=m>j5EF1!_qu_qf0_o_n0&8Q6o`8_{Md zhiH-!{7m!d8>5o$xwgBA;%VX@MDd);J&58tygS9jDo@=G{)nV9v^TI4vl;e^z^@0$ z*cKzi{3DHPs|;X+cF~o#N>f&Q7wOs|nTxxrNjqhxyl5AyB0O~CE;`yy@#r!V!KlN$ z{oAL%)~D}<2Wmh|V_0YcFiDNAQv*>0ynHa=LLG)S6Y<-@(WlP_Ip5OjuHv2}PaeA{ zFi!FA^cMF(TK5j)pOb|?gCE?JWn=1jTOk&d_|zzrUlf@fsBVN}&|52jRQ(+3G>z?qYj#phd!-lK@&kR{9%I;Xr=?s6#ff=*4%v-dA_Fe`*2?A3 zIk`P%s=vb?3hJaZWKVa{z)ngqJG6to>ZG)06L(O4C&jz*gUL_}`CUqleulEn_fXFm z(=YRTM!0=yhRzdUY@ZnTgH`yzMJ1Jgrl8JBm9k}b@XsVv+hQ8fS=m=H@mu6#P%dgK z{S0cxX3&01wYw<2*_&-Nw+jaFmTi{nU6kV*);ig;rkmoTVHun0hwe%&Yq6Q$bVoCl z-%K@nfHLzNO75XtXAd`7I`vdWYnazK%kg-nnuf)1q+1Ef7`A8(b?l`qX6-jv?)Ks$ z=HM6P*9TFZ*3+aun4(*)qvm}TcV=A2BUGiaeU-0WJht+3oW%zre8Ja#4OQ=_c(RXM zD6*f@!u=?&u=6Y1ylf2alEbYpyAXu){T9oLeu}e(m2Y9$+F!vl*>5{jqk&35ck3n$ zmHoW;@E2tWwo2cpMN^+l;xS7s_FrolHxc+&< z4LZfsv3MSUV{I14?1<y1sH1~uDZ zq^=%-&7;k2G>KuM!{Ij>#^FCYY*{!N?E{jektdov=E4VpwSXnLo3xu&Q`!jhuWPGl z#|Wr^_>$*;Aw zl#!iWzLhw$GxiQ%XJ~5<$85Tv4~C4;FIR#P@*p@vYa2#?j8vjomCh78N}1t55hzq- zZL_hgwP6LDZLvu^NPx;)FGJ!yw`sesq-&!vPgPh+)xLn9HD?4h|3Z1rf;&>Z(aK>q zz5_iOtqf#2{ix#@We_XqO?$>D582edw05jAmbnCw^El`n_iIu3I0)U{wP^G>Wj6Eg zLodcDJz4qBsqJ{+J1(I~2ilvV7^G|T)X<(`)PG!r)dSp2k` zNefbxT9&s{l{Sv-x2e=>rgE1RPa)WE4Pi^U>9|tQk$pbVa(IsNH|u|31YaVbx9$y6 z&wvINZsB!lS{?}z4pnri9lb)JTNSSP7kZ=}JxQQ_3$eKWN9^bkRAH`i!TIoX=)^UR zgYX%ZVfSQuHdpD8GAtSmt+i$%ChjHjf!R<$0of%W0f2N9kaYqQ3`ko6F$qXhKq3WX zihx7{(pW%-3WyPqx&qQ&K!yR*Y_I^e7ND^J1q(<60htU)O#$&%A*NZpXyLjl0;mY! zd;u&kfPdBHg)yny9pO4#Yx172#4|%{%ar-bAx9S9($aW=5~FGBii?6#_BplGvP@M7H38)teKn^6{; ziwS|)j5gS=)y@}QuGsKPe*xuR44w$L)LpE!(mL*R)L6zXS9WOF@rD*JQmQhxIoQ%{ zm9oo`y{bz^Yn9>(!JlK}?sg-tL?uO`9Roh6*XxuKzUBM!7RP;HMpKe{8yGhFxGLtt zRm4c7(mT+Sx?bt6VMqJXoefZ%hxH=2jY=XL(AzR|qtZyj>IBf9ud%i=$CJDXy3wC~ zso^H&8HzD0WeI+Ob&~&C2yAk1fzY>vpFR zTa+togD6Nk=lczBw=2)D`%GaRDA;v*^d~qnFM;lF}C;E=CIO|CA7B099G;k>~1*qJ)$&rof5(OSDwh5&G2P&%jP4>JPoTJK|#l` zv}vx;ren(Q>{K|-KaNFMMmS|3S6Z;xaMEU?Q~lYDdSzl}zS@kYW-8U#zGk#CQyEz! zwwc-;9vH(vjQ5BQd=?x2bYeyI^XK#UCeUW6-OS>DLRo=?%36+ODV;U!hZYu>Y^9Ax z_bY}bS6p#Kd$yrv&?#&!IfgPP%Xc}7zs6CgaU%G zZiA~&%jY_jzMFqBLUC9F`D#-@2kX}PaPXN+tYap(JkLc8|K&W!oZEb&vVY)mUrnP( zcZ0_<>$*MSHtsMriYl=+LS{07@CenU0OR863l?y7MTh{?pVCiUKzE0m0liY;@w!6- z57?*ATXF=B+b7vSZ*d6<5p=quhAKa99aM8d1RorADjWBFUg!kqk_y67J!589(lSj5vlk z!RG;zeu!{rU4+3CmQXi5cZX1mi%LXv1Cgeow(5$nJIoD)5!0uyJ9Yr8e%r zQYYms0I=ubhRs2XxWBl5&^);Mv?!?5*_Zx!3P`qo?tOF!Zv1?R)4c2B-x>)56M7b| zK5e1E>V8l;-0`h29ykXEy1G1Ph&&kX$$O{0cYNv>FT?EpBD*O57vK(PgM+EVCB-eWsT!$| zHj=wV@vy(^cLq%SBkehf7fHQj2KOA{_P;%3Ef>mg7aaDp2Y zdj(VQWyMXN2pIapu3+kTS@CZ0|PlaoJxQF+J z&)`uy&P?rWL&N&Rif`Bb=Yx7^J5Kc069e340*NqjIKSc;jspd zH9mCzy0V|$^|q`lP*!W$>`V&#P1#kZj3?ef!Ux1|7Isr9JY)Rk z+;iu!HGuWknUK?|5$_*U;Vs3+-W6IN-&T%lQuZwU3(DJsku@T46Gz*rvP%;u-*C_K?usd>hg+wOZUL?@S>bf}*1FQ)W%jAFMSN5)EeRALl{Af*%L1m- zIZ{CWv|u<*!nF^%1-fb3Ce7q`(>H~rXOK=s-1t%*U#OH{HKc?j%+(2bQn)81eu|Et zFY!&jbFElIv)vW)sXLxGCh?lqg-2=4?sr34BMmY=kV-kGf|XKMwR6*9>yo%0Cv>zV zIZKaN9itcCJhXo45+~<~)h#lseoT{gdG+5e4!Afs?!xf59*~#|!v*8Z#}@@$FE{SO@Y|;9!h0LW7}nkI##ZxT zIWzPaT2SYls%NjyYjpZHSlKDtrn&{lP+s_yTrfARm(EzMebX^#V*~RXw^uqJHdt3C zG))fXUi?&%+PTsSw&lDdw)fsur%1Al%pkD6%l+)4;X>30J zsC|y)8uhrd?wHlNU+ScgT4zW~TVmXNZpo1$YpEoe4hWw54Q(vuSM#MPdPFNlMSrO#q ztqVPaFa6!gojvA7y6t7YJ@iGo>qsl2Ss9!x8Z(CSy-Es~_GgcEr^pdel(aBz`%va( z7etlt<1}a6ukvu9dRP|DeXE@bxu5;^;R!4uO34R<%HXU`?gj)=)?Ycc(4buz<8jdu~F`Qwz$Z(b68-`Vy ze)YA9IBpofL$9cZVTR!l!;yyL45u2-HC%4E#<0S0r{Mv^qb~W-f5t?3J}_I%u$N(` zVYaih+3Gl8z6mZjeA%$l@MFWnhQAsH#`GIb*eUC>@SJ+5&nas}uX4vz$T?f}sL(7q zrdj)m<;KU~tC^N(6*^(p+o=h@2CtivaX_c+ZuGb*o!&le)rWf7SWxH812vBRV2= zk7nGhdcnX7a&M;d|DG3{&?gWRD02UAsxrld2M6Of9~c+=-KE3g7V4t2UWj!&rKMJP zPW;nmRlkYfRIK9*e-ocx`lPiu7R8}fs5NS{*;*X`)SqtOI4^vx)Qr!5%7=Q5vsJI* zdOHWwjxRtKId^f!pk^t)-02Kp8t6YqZ@xJf+I% zGuoaiTs7M6+d=Z|`kh`+9m~sKW4&{HwB6fXzRaYl2B+ukc3)X;g5mPp?Ik^Te`~28 z1A1Ow%xU>EVqA{ttPWRNiQ(@bD*?wN`v!Vwmnkv z_q)SR?kx43PkzZ;X7Wm1 zEe%fJF?PSUJ&)=>OtQk2)h9ZO^*uJmo-FGpH)#Q`>zmE;d{ybzug)wd^_J~PzlV?4 za!%Y~cMRQYuFGYwDfz*fkZTWV`>`qF+}3ioPn|axNc6Waf z2{Me5`I=AuE`hS*HN;Cn=PKw?1*|aXiWt>3zpv_?p03)4^-+<0&XF$7A}w$Tt1>J5 z&XjS|gk>ndY}ONg#Jxemxhl`TQXd1QHLOuqo^nFhb_kS8j5J~2j?K^I*`veV0jyX+ zG8d94Ty)|;4pd$LAYFdK8S)2vnEzw)$yN<*k(6O4M61~8F?CVC$ef5QISBEl@f&p6 zbu8247Z#G`+J>pfu1fWPkq<)>?i{V!|AX|#`+{ah4?TlQdz`vF!Xha3Rh92 zSDaOw+f1>yhg~M6SD4b{PwJX?g3`>uuHNHZ*tsCrZtsqw7&n8{c`8jxKj{pdYL9L^ ziHzLarJFR;J@&4fYA3t>IiHn`H2qmfKKWZ@_y&|NBrwzj`znq8>ZSFWqmVzY)6jipZYjA$hq6c zqOkQej&X3vG##Ei&F(4T=cd^cg}+X-X9#CZr`~YebbE|2`9Y3daP)&5-^!+ksdrKS z99wmv-8$?nCr$Ev{2&8gHkS9mld1lZnE4sm9`>Gy}2?>wYX)l zFa0)-cPT_wbG7gv@oe(uNY%hC;9drF+GDy7q2Z*fTRRWr+viJVmgL)=g&Xtju5P7# z^mbDBDAhjwD%GAnESfz`DqAS=sZpw3Sf+~fMWltB_$G-zKSITZC923YowtI9C0)#o zEa{i4Heo%L#}|_mC`Wd{9F&Q|Y>%?jW0l>fRa0!8*SX~(yH)Rs*TdA66+DjkxUP9< zI4LDcwN3BFuHV^I%z5e|JNa^{U>bW@Qs*cYAJ*&NDwq|lVAo&;m2=`D1_JH2X6W|! zoMDek%B&7kpP=lydeyZ z@*EzjQh16}9{8*?#RkL9m4CFmNwH)8X!lIY>`}U_dWUqCGp@j%l@$MExcVC^nWt+J z3_B+Z?2D2ro(@;f6@{z)COH^(E}vOgYO_oaAC_r5OYfb-X6e0l;w-!8UDBX3wnCTdEp>f! z2bEFVQC(J@s5<8+smM{u$~QhjJ&p3_Q`*zR|oteU=1?oOK@t>X7bsC&@-Jkxg};iU5zBbw z-gwyV?alf!LjCbzger9!9=6X53AUPTUofJuB|^3QGeR{lpv23g)#c4?RqEk(%9Eeq z#t-_LQU8>zEmA4c6lsz_5TA5@Bzxe6O7>SeaMov@^Uk?L!m=ATvm0}cZX!>ofzf(bkn{FouNxjkT-p*{w4|R4 z)3+=ex?EVYrIPc#DmmAql1Ig;af#$jy*BS z-Cm5MF5E%sEx%bcHAM3*IA60m8|K&-B-LEaEqJK-XZhkcExWg?5i@AC?k%?)2vzf83s&RQGO-YC(z1bos%sGi|PY zNm3Peq5lhIo8(~Fc}tSZs$$e0RBDogVdtN7^`SNS34M~f&TxX^Ji~Q{pBkQoJ!SLz zm?KVV$93i*eICzYI44~Yt?aOl`sAjMBG=8cyCzj!uy5!LT!Po_$_Y84oQs zpd6DN3_BaUCgW1(@`L7w~=douJakqZTiIe0?W-N&vG=@ zEVl*!XE*GOSYUVP5U9^D#2s15Cn)kAS?SDLV2||6CxLj6uFuF<^k)kFVcly!taE`% zI@jrEH=6PvdsTmlu@=f-(!YJUXJec4E-U}<<;^$ge=Yai=oWm`WE^e^wp-DW6WB&n zu7b?DExJSO;5Rf3IB%@l_L{E9!PlH+PuU|Z$?xkFtKMyKjy|Qot!cYZ?*x4p@-11Q zBmTzI1wWxJH0Y--&SMMhp24)G+qsTFzvH0#!FFfILiU%eou?+cip%Ak@U*~2d$rD^K1KJi9-)N!i5xYbu>6I^ zM5vg7@=;JZ?=P}%x;U`l&3ip+&gXiBy$fGLLK%TVud{Ta-7eUklSJj!>f}djoiU5; zm2w{Vd9gi9IAe*v@O^HHK06*-qCeS;dD}KU&_SeKzgzPRUrMD`@L$?R8Bvqozc(mwQeB($3J*gzbS6~s%Px3 zqXY4Op5|2*)A^aP(}4rTe-6xnoX)aQQXo$>U-S0SJEC;ltOvcS2#q@JBp2Js!9oB0 zLtga@n#^*8XL!|r*{JF+(kG&%)6V2#dt`9gOZ{GT6$-BNzw9t49`&k!A(lN^Z1)Ma zb@4nepSs-mzR&7|*tloyiSDQJOzJD&6eZ-c@!0`G2f*~LUbPzq*D2RiTv1vhql1H_ z`^R3j7CrHQ>5HFt)6PB8&*mV+!L(C;N7X5}gEQzk``X~B{HVsOzCgj1{g(#b^qE(U zNB>ivrKE5FU-Iy4E~=x>;X=huBogCa+1Ap4L(1CM+EQt4_#E()bM$$;b8sD}J6P(9 zj+VOMCntHiJy4b(w_LC5(dGK|wraWEr%zy=mv-j#gra^jd&O@?{Fw_Z)icFn6gbf@ z=>F^dLdf3s0f*(Vi`@0idLg79QI}cj21Gs9yM5d=m%N8mlVsSyzAAm2?T8N%EWdT=Jtz4r@~8kp6Y4-67cK?}uCJ>YFXq_a`TM z1xJ=Z+XfD?)K@ohm^$rTx58c`b@+6J?u+B(lW>QXn%Aui>63#Gat(%V3G|6vtA(60 zR+ILQo9?Vysr&f5m3&1WSnuy1eeHSl%=a$ohaxS8rR8tO@ z5t4Q>J3{Wos^h30sw3$gNsrg-nO*UhzjAnYuC$sQCX&8TtiSZ1HsReFWY1)*y*r}X+l~#ah2Wuia;-(e}wPoQ4{%vVXebdYqmn*&v&PG6&1E~!C zZ%R3VeDMSANT+JG9nXCRlUCd3MbwekU0(}%bv`F$5Sdce*zw`{-#C5N*vrD|-2$AN z8|+AXC-b!+xtBO;x)*c(-d(&RprTue1 z$42_4@txk*A13Nf2l z?E~Ua6~1D7m`Zsczm0Ez`9iaZ_=+mhMZ{O|gl0uWn9BK6n95qut@oK5$h4USNXX&c zB^9is3Z>x7h^ylDB|b8%w@AaM5uZchMW~GBDyU!$@lB`>#gksc@=BgG!8hUS(4{o; z8Z->ujwT@A+kRUu#;ij-(ce)EO4w|x-slE&H=2!BqIb|f)Py{hwrY>MqTc9Q^m}wS z`U9GY=A-A)IjW_MQ|IuMFjj zia?sM;x3&(bDU<4p>Mnn*G<&)-RF|;pz?G?nPJWx9d0r#d`yQ^9^cH7WW;6uiIc)q z2J>@1xbc4NE8xBd!qiye>tJu@0mY}m=aFv$HzC2m{Gf2&gJEhmd4zAEB77Beo(WT> z_mLkCewG6*@mcU*CroXcWBZj4)18UJ8d(7hOc)A%Wns$0lhpB{nxVekKP3x%<37kt*e@-R) z@p4MJpYv4{Ud~(1$itkToX6IpPWaHdJ(=^Hk46zM+<@{V4;;g(rvNXfpdUAdsjZJv zj-PYU6P$aBNRV@o!+B~wUe009bFQhz%L(#9PL%uca>D#OCrj~i(!7;(mv}jk%}3Ho zIiFP;FDK6qoGjz+vE7sD4CCbl`YYzIm52!%$vYGpPYfWa3=17moxJB zNb<;;dMan*{=~~!xi@F$q4?lbBVMK;8&NJ^sQygr@xm>;s4Tu}7iaAbdl?i2QegGx z3_wn#HSmJJ5teuun0OS*FMYHSFKqh-6=KRz9SBp`GSk=zA36gmGm)v^usMhq_D1>m z;B?{>tSoe{QRW<<{5yk(Ou{m>3orZ{?Z?-_y@z-jNebd86;?ISI%X0pU~wbk178Ne zKh7lvz6oB-PXrCcXTsFS!c`7F4Swn8pX?HK@Wm&>Re>xFBbmLNj}OjV;$=p&V1Br& zzzc6@8gmyuIDLtiY0VU7teWw{w~>eW%PKgV`OHLoa2^xymkG`ryb)>?0bx6fSw?&c z+}Aon72s8y2=#7!guACy!I8{%mJ%O2(U-G~knE0HF4^DvMWg;}^rwCP!7y4TwR1H3K8Z1X~?<~dg-MygJDVISr) zGw>mEn(kcZZA@wA5-%)9i}1l|O}tEZe%LosmEwib%x_lXgL9jBne+VT&5^1FFZ2%@ z5vdZHt;~Xdz9Ulgzz1h3@u4%AGL!kqd{#`nFnK|wD#r^mP$fPSKCmKE?ZVf=ADG%~ z#s{Y~nc|eG&a9m@coD~cF}I@rB;>&I_$W0TUje_equhn-;AKfsDwp^)7=2!pS|kO* zO&g`aar)7gnKzc;RbTF=r{eE4+R{v}z#pl0HQn~;a8(<(UND<&oJS@2tCS<~>r*;c&Fx_-!1Yau>3 z&5D=l*QNbp)EYeWt7QbX5-5W^dD()Tj%%PZB1Y|&cvzJaqZ;wT>S-~`!{ldha+YqC zN!tf_b508JLLW-U3&-=89_jWRc(RZuEQvoibIb8xrgT@Ku_OprBOg9=IyQ8=R;F?L zqZ0B6hoJR%VIJCw_ravOdc`Sl3$wO0#Gjk3wcS}<%l}l2Y9hgcZBYu-uqp5e)3<5( z&}mzl&Xwue9O6T#X=VEMG%A*OxZrszgfD^ka+E2V+%(Yvn z1c4^F@7)*`$*gQ}J{K?ZyzeoYn~E21LqqYwNnN~5_7*Xtn~N8gphfuL%r0JLe4qOu zMwR1*D?ecS*GMJ;MZC1K4lmqUOC_FR8^e^ZV^j~k&|lB{I`D-st%c2m7jELc$>OV^ z)sAT`d^|jy>QR;WCKz>vM;*kcKzUWITq%`Z;XgOSD>J?C@s+cW`B>oxXfD169=(z; zvG7gsN8a}L9Of6Z{Usrvzyg!72sR?w#==g|>O8_U}KY??AHfShyMGlBW{>grstbWgc}q5?=sIQ02pH8lmx3aONs{i)D*edHm|Y zY6c8}gK+*DwkLi){1C~?YGB-2z1s+f8lMH9MzXRZcmP%AQVu*To)xQ?J*pcLp9+0Q z8Y6rS#ofd4e?8_0B>QC(?D~pcaWD7`T0@13p;fLIj)M=OCgKZV1(Hfs!rWImPL!~j z;4xH1o)GX4K?eKF`J;2OToi z!-w8sU*;5C0AEFte?1(!#iLrtQvt)?W#m6^t4KHoNmq}B^N=)bK5R7c!nd}v{Wsl5 z*KOq<+HH(Z7EXXyzVBfVpp|esl7;i(he%qs3m!mHiG%RC@lDWErSl8rmI_%`xB{h9 zW*NM6J7WQ#w%yORAt0Hu;YVmL2{rJniBH|(QB#quOl~iqWjv4dsddIz!Ou}S%htj6 zAF|8I3ScIx#Am^}UECfddElgvck`6kKThA~>O5=g)<&BFVEJ zo;1E0_G{4b{r#B5NJe!LJb|Qpn_;)3`Z^#LPC$!jWg#pP;mhDls1#oT|Afl$>KKC# zmE*IZgDUVmN~<K@`DS#{C(Y=5a;Cgu@Tx`GwJ_fP@83NHMC0}2Z-g14X0J{$J@ zQTtwSKayS<+RPCR$@hbY;nSzIFM_>JYcJeyJoKwEKXK0$D;o>zQDZ6F5)Nw73k-&D zpi$)61PA?7_ts!I?Pu;ABY!?z`!DUwVf!;WPa@oc;>fcV=KR7{7GC(^Sx$H_aQx55 zEDH0wEf6k?@RGnthT+jnnlmOM;T(_lb73=*o)hMIwHHQMUUySQ!WWS25v8zWoc4+E znO52t!@mADI*hoxLi9{LS#%E?%_@p9xPQ8FT(-%<`_Rm_b(xuTRyj$%G9TYTpPy?5^Uyu_>a6JG&W^zt%mM+?e&dDWmxz3#Rj3>#1+ z@s02+ZlkJWbJW4lFY~I|EL;o6r?EMR&w=K1@cQd@PYi|iXgK+W9`5TJix*yl-0T1TnDha(j09l;lEEc>dm#7s5MK!oA?e=3 z@b*Do_kuGUeq#J?c>Q17y9q!Um1a1_%)J)PaV93 zo4uqG>2NucR+hpqQOb)H3Nwf5{KCK8UDZwkZ9&0^a}cvUW5*z*<| z^CHLpUYIwLtauaLGZIgx8u-i|UbO~a3_n1!U8~`b#`hoNRZk%q$&286@l`NgZdAkfhkrm)xhW5_ z|CbS{BViM~mb=lUcA2mM^;*RyfLYwZ7Ka}T6aUD*j2BKoQcx~@-}pvYK2skvgi*6} z9uIu_Vaj6JB6tQR$o0RN=tnp-&S1ZUH=$fI4Tl#zN>AWZU_T@+?hi*BpADZez8LN{ zz81D&Y;9uMc=$V1BxS-jb9Ck6;T`_R^lmc+zKrIRsUGqQ2vvyZy$R|*BrE1!3W`@j zxL&vix!V{{oU8q8ScD|Mu*`VjKI8YpdgJ|KhCiXZUAO?byA!NMvI5>Cp)Q)I{a`pA z$qIaM18Sk76%x0Amf?lfXg^-~Ba-~haK=;m=ve??d5Y~X3FQP1An^xb>_Y8%NrY-H z;w-nCFJU(~?NqjxLa4Wkj z@mX8h9!ChQCr}T!ZPS~h3buYY2P36juE%k!e5YlA*DXzIslcdrj^k9vCb0* zx1n0%tDyQs#|w|4#5ME~{Ksy6T;cU1s@opM&1#PSykkV=BB_yZ2a@ip7XF3Saru=1 zOKLcXP>^svlHj-UYt z;iw~&L;MtY&3C$T{ozAMK1US5?~p&^WonA)T2G<)RCqI*i_d~zqh9zrIH7?aDr9$p zE0G-A%izGHdTH+VZXMPN-gL5zdz<1lt`cse%p?P z@Q2~A3EHdnmYU9Oyt%~Z!v{Ok6BLvWqj_9U5$}QZXg*%J`#ejP;Dwty5l@c_SDdeX z8I132`BmY)oFcj3cMd9Nfw}NP?(vnH_JD_w92*Y9Yf~tgJY(UIF1$jAYlWe3byw}z zKr5B}uW}g&U%Qa|MaiGp-BN?NCpeAx!SE|26>7T3Z>jGuw$xS|9^u4(mb*vf!KFwxWifpE z8hXyZjzcMCcz>NBy!u*8bt1k$+;}~;##cgbrXCY92-dcUSOqod6m0x0xU+d{e-nh#z(Jg@{A!5%L=c#lTC*2562)mHjIUf$Ki=Dg0si7 z{pCt`_IPe^znj8HNQ8A0=vKUNaW35@3qb2$y)xcH#=xaz>uDuiGtpB0@xsgUEY%BN z3_n0_55XUeZ-(6_>G)JXX3!KyH46-eH%;Z$EqpQ^4mbGNg@~_!bEnf{yl??`dRO2V z!Cfd1FKj_W@hYD?p;5iW!*vgFS2WiL>)}^ODl}yVd)6P>{?fg11#~-_vYG^#z^&qv zNjMj&4XhY8AnEEx_}VNz7}vv>7Sj{tSpy@M=w%~e>!;ZS#Pd!sHME#x30}y%yxes` z=6@XyCTxOYcofNYZG=5v&7}%ig@rqjRALu=ZH1{2T)L8i$x{sPeo@Eg!e5P7 zWtMt#HI*aJCb)79y}N)p3WmR~*A)q0_nSZkysU!#l&{#+;CpYdViv9u zqHGpUdDBvNq8$8K_#TpTM5nhb?m?!9h;N3AHtS6wTvO@pW~vch^Nx=14?Aqp#~6Pi z=1Ww}!Uy5~?^*hbCphDMi%A5IhVbet_6~f1_z99L-QDn4B)gW{&M~5z6_7_Lx8oni zhu)Six99(1Clz{~`XAo<5ew#^b7W&3Ql0K?*VlEA*lW>5j{johIax^%$}_0qh4QSac;RZ}h3_J% zgisy_l|1fap{KQ%M-b)7L5Ua2Bc9@gql_0$_M3n_rzy`hN+zK^?I&JXX}nOL#FKcT zJRv7uc!BZ4zQzmXi809|%rjm%$M|c+$OBN79IJ)jBWamD(() => hasher.Digest(new byte[20], null)); } + [Fact] + public void Lyra2Rev3_Hash() + { + var hasher = new Lyra2Rev3(); + var hash = new byte[32]; + hasher.Digest(Enumerable.Repeat((byte)5, 80).ToArray(), hash); + var result = hash.ToHexString(); + + Assert.Equal("c56ec425ada2c8ddcb8d5a79a3a0c9d79f66318193049fb81f875c537a4f963d", result); + } + + [Fact] + public void Lyra2Rev3_Hash_Should_Throw_On_Short_Input() + { + var hasher = new Lyra2Rev3(); + Assert.Throws(() => hasher.Digest(new byte[20], null)); + } + [Fact] public void Sha256D_Hash() { diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Lyra2Rev3.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Lyra2Rev3.cs new file mode 100644 index 000000000..fede897fd --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Lyra2Rev3.cs @@ -0,0 +1,43 @@ +/* +Copyright 2017 Coin Foundry (coinfoundry.org) +Authors: Oliver Weichhold (oliver@weichhold.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +using System; +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms +{ + public unsafe class Lyra2Rev3 : IHashAlgorithm + { + public void Digest(ReadOnlySpan data, Span result, params object[] extra) + { + Contract.Requires(data.Length == 80, $"{nameof(data)} must be exactly 80 bytes long"); + Contract.Requires(result.Length >= 32, $"{nameof(result)} must be greater or equal 32 bytes"); + + fixed (byte* input = data) + { + fixed (byte* output = result) + { + LibMultihash.lyra2rev3(input, output); + } + } + } + } +} diff --git a/src/Miningcore/Native/LibMultihash.cs b/src/Miningcore/Native/LibMultihash.cs index 307de3ac7..c5434b1f0 100644 --- a/src/Miningcore/Native/LibMultihash.cs +++ b/src/Miningcore/Native/LibMultihash.cs @@ -124,6 +124,9 @@ public static unsafe class LibMultihash [DllImport("libmultihash", EntryPoint = "lyra2rev2_export", CallingConvention = CallingConvention.Cdecl)] public static extern int lyra2rev2(byte* input, void* output); + [DllImport("libmultihash", EntryPoint = "lyra2rev3_export", CallingConvention = CallingConvention.Cdecl)] + public static extern int lyra2rev3(byte* input, void* output); + [DllImport("libmultihash", EntryPoint = "equihash_verify_200_9_export", CallingConvention = CallingConvention.Cdecl)] public static extern bool equihash_verify_200_9(byte* header, int headerLength, byte* solution, int solutionLength, string personalization); diff --git a/src/Native/libmultihash/Lyra2.c b/src/Native/libmultihash/Lyra2.c index 350530040..05ee86211 100644 --- a/src/Native/libmultihash/Lyra2.c +++ b/src/Native/libmultihash/Lyra2.c @@ -380,3 +380,194 @@ int LYRA2_old(void *K, uint64_t kLen, const void *pwd, uint64_t pwdlen, const vo return 0; } + +/** + * Executes Lyra2 based on the G function from Blake2b. This version supports salts and passwords + * whose combined length is smaller than the size of the memory matrix, (i.e., (nRows x nCols x b) bits, + * where "b" is the underlying sponge's bitrate). In this implementation, the "basil" is composed by all + * integer parameters (treated as type "unsigned int") in the order they are provided, plus the value + * of nCols, (i.e., basil = kLen || pwdlen || saltlen || timeCost || nRows || nCols). + * + * @param K The derived key to be output by the algorithm + * @param kLen Desired key length + * @param pwd User password + * @param pwdlen Password length + * @param salt Salt + * @param saltlen Salt length + * @param timeCost Parameter to determine the processing time (T) + * @param nRows Number or rows of the memory matrix (R) + * @param nCols Number of columns of the memory matrix (C) + * + * @return 0 if the key is generated correctly; -1 if there is an error (usually due to lack of memory for allocation) + */ +int LYRA2_3(void *K, uint64_t kLen, const void *pwd, uint64_t pwdlen, const void *salt, uint64_t saltlen, uint64_t timeCost, uint64_t nRows, uint64_t nCols) { + + //============================= Basic variables ============================// + int64_t row = 2; //index of row to be processed + int64_t prev = 1; //index of prev (last row ever computed/modified) + int64_t rowa = 0; //index of row* (a previous row, deterministically picked during Setup and randomly picked while Wandering) + int64_t tau; //Time Loop iterator + int64_t step = 1; //Visitation step (used during Setup and Wandering phases) + int64_t window = 2; //Visitation window (used to define which rows can be revisited during Setup) + int64_t gap = 1; //Modifier to the step, assuming the values 1 or -1 + int64_t i; //auxiliary iteration counter + //==========================================================================/ + + //========== Initializing the Memory Matrix and pointers to it =============// + //Tries to allocate enough space for the whole memory matrix + + + const int64_t ROW_LEN_INT64 = BLOCK_LEN_INT64 * nCols; + const int64_t ROW_LEN_BYTES = ROW_LEN_INT64 * 8; + + i = (int64_t)((int64_t)nRows * (int64_t)ROW_LEN_BYTES); + uint64_t *wholeMatrix = malloc(i); + if (wholeMatrix == NULL) { + return -1; + } + memset(wholeMatrix, 0, i); + + //Allocates pointers to each row of the matrix + uint64_t **memMatrix = malloc(nRows * sizeof(uint64_t*)); + if (memMatrix == NULL) { + return -1; + } + //Places the pointers in the correct positions + uint64_t *ptrWord = wholeMatrix; + for (i = 0; i < nRows; i++) { + memMatrix[i] = ptrWord; + ptrWord += ROW_LEN_INT64; + } + //==========================================================================/ + + //============= Getting the password + salt + basil padded with 10*1 ===============// + //OBS.:The memory matrix will temporarily hold the password: not for saving memory, + //but this ensures that the password copied locally will be overwritten as soon as possible + + //First, we clean enough blocks for the password, salt, basil and padding + uint64_t nBlocksInput = ((saltlen + pwdlen + 6 * sizeof(uint64_t)) / BLOCK_LEN_BLAKE2_SAFE_BYTES) + 1; + byte *ptrByte = (byte*)wholeMatrix; + memset(ptrByte, 0, nBlocksInput * BLOCK_LEN_BLAKE2_SAFE_BYTES); + + //Prepends the password + memcpy(ptrByte, pwd, pwdlen); + ptrByte += pwdlen; + + //Concatenates the salt + memcpy(ptrByte, salt, saltlen); + ptrByte += saltlen; + + //Concatenates the basil: every integer passed as parameter, in the order they are provided by the interface + memcpy(ptrByte, &kLen, sizeof(uint64_t)); + ptrByte += sizeof(uint64_t); + memcpy(ptrByte, &pwdlen, sizeof(uint64_t)); + ptrByte += sizeof(uint64_t); + memcpy(ptrByte, &saltlen, sizeof(uint64_t)); + ptrByte += sizeof(uint64_t); + memcpy(ptrByte, &timeCost, sizeof(uint64_t)); + ptrByte += sizeof(uint64_t); + memcpy(ptrByte, &nRows, sizeof(uint64_t)); + ptrByte += sizeof(uint64_t); + memcpy(ptrByte, &nCols, sizeof(uint64_t)); + ptrByte += sizeof(uint64_t); + + //Now comes the padding + *ptrByte = 0x80; //first byte of padding: right after the password + ptrByte = (byte*)wholeMatrix; //resets the pointer to the start of the memory matrix + ptrByte += nBlocksInput * BLOCK_LEN_BLAKE2_SAFE_BYTES - 1; //sets the pointer to the correct position: end of incomplete block + *ptrByte ^= 0x01; //last byte of padding: at the end of the last incomplete block + //==========================================================================/ + + //======================= Initializing the Sponge State ====================// + //Sponge state: 16 uint64_t, BLOCK_LEN_INT64 words of them for the bitrate (b) and the remainder for the capacity (c) + uint64_t *state = malloc(16 * sizeof(uint64_t)); + if (state == NULL) { + return -1; + } + initState(state); + //==========================================================================/ + + //================================ Setup Phase =============================// + //Absorbing salt, password and basil: this is the only place in which the block length is hard-coded to 512 bits + ptrWord = wholeMatrix; + for (i = 0; i < nBlocksInput; i++) { + absorbBlockBlake2Safe(state, ptrWord); //absorbs each block of pad(pwd || salt || basil) + ptrWord += BLOCK_LEN_BLAKE2_SAFE_INT64; //goes to next block of pad(pwd || salt || basil) + } + + //Initializes M[0] and M[1] + reducedSqueezeRow0(state, memMatrix[0], nCols); //The locally copied password is most likely overwritten here + reducedDuplexRow1(state, memMatrix[0], memMatrix[1], nCols); + + do { + //M[row] = rand; //M[row*] = M[row*] XOR rotW(rand) + reducedDuplexRowSetup(state, memMatrix[prev], memMatrix[rowa], memMatrix[row], nCols); + + + //updates the value of row* (deterministically picked during Setup)) + rowa = (rowa + step) & (window - 1); + //update prev: it now points to the last row ever computed + prev = row; + //updates row: goes to the next row to be computed + row++; + + //Checks if all rows in the window where visited. + if (rowa == 0) { + step = window + gap; //changes the step: approximately doubles its value + window *= 2; //doubles the size of the re-visitation window + gap = -gap; //inverts the modifier to the step + } + + } while (row < nRows); + //==========================================================================/ + + //============================ Wandering Phase =============================// + + uint64_t index = 0; + row = 0; //Resets the visitation to the first row of the memory matrix + for (tau = 1; tau <= timeCost; tau++) { + //Step is approximately half the number of all rows of the memory matrix for an odd tau; otherwise, it is -1 + step = (tau % 2 == 0) ? -1 : nRows / 2 - 1; + do { + //Selects a pseudorandom index row* + //------------------------------------------hg7------------------------------------------------ + //rowa = ((unsigned int)state[0]) & (nRows-1); //(USE THIS IF nRows IS A POWER OF 2) + index = state[index % 16]; + rowa = ((uint64_t)(state[index % 16])) % nRows; //(USE THIS FOR THE "GENERIC" CASE) + //------------------------------------------------------------------------------------------ + + //Performs a reduced-round duplexing operation over M[row*] XOR M[prev], updating both M[row*] and M[row] + reducedDuplexRow(state, memMatrix[prev], memMatrix[rowa], memMatrix[row], nCols); + + //update prev: it now points to the last row ever computed + prev = row; + + //updates row: goes to the next row to be computed + //------------------------------------------------------------------------------------------ + //row = (row + step) & (nRows-1); //(USE THIS IF nRows IS A POWER OF 2) + row = (row + step) % nRows; //(USE THIS FOR THE "GENERIC" CASE) + //------------------------------------------------------------------------------------------ + + } while (row != 0); + } + //==========================================================================/ + + //============================ Wrap-up Phase ===============================// + //Absorbs the last block of the memory matrix + absorbBlock(state, memMatrix[rowa]); + + //Squeezes the key + squeeze(state, K, kLen); + //==========================================================================/ + + //========================= Freeing the memory =============================// + free(memMatrix); + free(wholeMatrix); + + //Wiping out the sponge's internal state before freeing it + memset(state, 0, 16 * sizeof(uint64_t)); + free(state); + //==========================================================================/ + + return 0; +} \ No newline at end of file diff --git a/src/Native/libmultihash/Lyra2.h b/src/Native/libmultihash/Lyra2.h index 6ff09735c..613e75db5 100644 --- a/src/Native/libmultihash/Lyra2.h +++ b/src/Native/libmultihash/Lyra2.h @@ -41,4 +41,6 @@ int LYRA2(void *K, uint64_t kLen, const void *pwd, uint64_t pwdlen, const void * int LYRA2_old(void *K, uint64_t kLen, const void *pwd, uint64_t pwdlen, const void *salt, uint64_t saltlen, uint64_t timeCost, uint64_t nRows, uint64_t nCols); +int LYRA2_3(void *K, uint64_t kLen, const void *pwd, uint64_t pwdlen, const void *salt, uint64_t saltlen, uint64_t timeCost, uint64_t nRows, uint64_t nCols); + #endif /* LYRA2_H_ */ diff --git a/src/Native/libmultihash/Lyra2RE.c b/src/Native/libmultihash/Lyra2RE.c index 3f7924900..dbea56060 100644 --- a/src/Native/libmultihash/Lyra2RE.c +++ b/src/Native/libmultihash/Lyra2RE.c @@ -108,3 +108,30 @@ void lyra2re2_hash(const char* input, char* output) memcpy(output, hashA, 32); } + +void lyra2re3_hash(const char* input, char* output) +{ + sph_blake256_context ctx_blake; + sph_cubehash256_context ctx_cubehash; + sph_bmw256_context ctx_bmw; + + uint32_t hashA[8], hashB[8]; + + sph_blake256_init(&ctx_blake); + sph_blake256(&ctx_blake, input, 80); + sph_blake256_close(&ctx_blake, hashA); + + LYRA2_3(hashB, 32, hashA, 32, hashA, 32, 1, 4, 4); + + sph_cubehash256_init(&ctx_cubehash); + sph_cubehash256(&ctx_cubehash, hashB, 32); + sph_cubehash256_close(&ctx_cubehash, hashA); + + LYRA2_3(hashB, 32, hashA, 32, hashA, 32, 1, 4, 4); + + sph_bmw256_init(&ctx_bmw); + sph_bmw256(&ctx_bmw, hashB, 32); + sph_bmw256_close(&ctx_bmw, hashA); + + memcpy(output, hashA, 32); +} \ No newline at end of file diff --git a/src/Native/libmultihash/Lyra2RE.h b/src/Native/libmultihash/Lyra2RE.h index cfdb3663d..a8c270624 100644 --- a/src/Native/libmultihash/Lyra2RE.h +++ b/src/Native/libmultihash/Lyra2RE.h @@ -7,6 +7,7 @@ extern "C" { void lyra2re_hash(const char* input, char* output); void lyra2re2_hash(const char* input, char* output); +void lyra2re3_hash(const char* input, char* output); #ifdef __cplusplus } diff --git a/src/Native/libmultihash/exports.cpp b/src/Native/libmultihash/exports.cpp index 1492fa74b..09f726800 100644 --- a/src/Native/libmultihash/exports.cpp +++ b/src/Native/libmultihash/exports.cpp @@ -207,6 +207,11 @@ extern "C" MODULE_API void lyra2rev2_export(const char* input, char* output) lyra2re2_hash(input, output); } +extern "C" MODULE_API void lyra2rev3_export(const char* input, char* output) +{ + lyra2re3_hash(input, output); +} + extern "C" MODULE_API void x16r_export(const char* input, char* output, uint32_t input_len) { x16r_hash(input, output, input_len); From 1f58f3760c216403b25d233725af883a14da1304 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 29 Jan 2019 09:33:00 +0100 Subject: [PATCH 096/178] Fix linux-build.sh --- src/Miningcore/linux-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/linux-build.sh b/src/Miningcore/linux-build.sh index 33ef1fed0..a38894480 100755 --- a/src/Miningcore/linux-build.sh +++ b/src/Miningcore/linux-build.sh @@ -5,4 +5,4 @@ BUILDIR=${1:-../../build} echo "Building into $BUILDIR" -dotnet publish -c Release --framework netcoreapp2.1 -o $BUILDIR +dotnet publish -c Release --framework netcoreapp2.2 -o $BUILDIR From db36d36edc57ee7072a5819bccb9cdd317f698c1 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 29 Jan 2019 09:46:16 +0100 Subject: [PATCH 097/178] Update Vertcoin for Lyra3 Hardfork --- src/Miningcore/coins.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index f97c7cdb2..2139136a9 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -257,7 +257,7 @@ "hash": "sha256d" }, "headerHasher": { - "hash": "lyra2rev2" + "hash": "lyra2rev3" }, "blockHasher": { "hash": "reverse", From ec10a5890dede6e0f00866e8b3025f94a7ba8b04 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 25 Feb 2019 14:14:06 +0100 Subject: [PATCH 098/178] Cryptonight CNv4 (aka CryptonightR) support for upcoming Monero hard fork --- libs/runtimes/win-x64/libcryptonight.dll | Bin 141824 -> 198144 bytes libs/runtimes/win-x64/libcryptonote.dll | Bin 439296 -> 386048 bytes src/Miningcore.Tests/Crypto/CrytonoteTests.cs | 45 +- .../Blockchain/Cryptonote/CryptonoteJob.cs | 10 +- .../Blockchain/Cryptonote/CryptonotePool.cs | 3 +- .../CryptonoteLoginResponse.cs | 5 + src/Miningcore/Native/LibCryptonight.cs | 83 +- .../3rdparty/rapidjson/allocators.h | 271 -- .../3rdparty/rapidjson/document.h | 2575 ----------------- .../3rdparty/rapidjson/encodedstream.h | 299 -- .../3rdparty/rapidjson/encodings.h | 716 ----- .../3rdparty/rapidjson/error/en.h | 74 - .../3rdparty/rapidjson/error/error.h | 155 - .../3rdparty/rapidjson/filereadstream.h | 99 - .../3rdparty/rapidjson/filewritestream.h | 104 - .../libcryptonight/3rdparty/rapidjson/fwd.h | 151 - .../3rdparty/rapidjson/internal/biginteger.h | 290 -- .../3rdparty/rapidjson/internal/diyfp.h | 258 -- .../3rdparty/rapidjson/internal/dtoa.h | 245 -- .../3rdparty/rapidjson/internal/ieee754.h | 78 - .../3rdparty/rapidjson/internal/itoa.h | 304 -- .../3rdparty/rapidjson/internal/meta.h | 181 -- .../3rdparty/rapidjson/internal/pow10.h | 55 - .../3rdparty/rapidjson/internal/regex.h | 701 ----- .../3rdparty/rapidjson/internal/stack.h | 230 -- .../3rdparty/rapidjson/internal/strfunc.h | 55 - .../3rdparty/rapidjson/internal/strtod.h | 269 -- .../3rdparty/rapidjson/internal/swap.h | 46 - .../3rdparty/rapidjson/istreamwrapper.h | 115 - .../3rdparty/rapidjson/memorybuffer.h | 70 - .../3rdparty/rapidjson/memorystream.h | 71 - .../3rdparty/rapidjson/msinttypes/inttypes.h | 316 -- .../3rdparty/rapidjson/msinttypes/stdint.h | 300 -- .../3rdparty/rapidjson/ostreamwrapper.h | 81 - .../3rdparty/rapidjson/pointer.h | 1358 --------- .../3rdparty/rapidjson/prettywriter.h | 255 -- .../3rdparty/rapidjson/rapidjson.h | 614 ---- .../3rdparty/rapidjson/reader.h | 1879 ------------ .../3rdparty/rapidjson/schema.h | 2006 ------------- .../3rdparty/rapidjson/stream.h | 179 -- .../3rdparty/rapidjson/stringbuffer.h | 117 - .../3rdparty/rapidjson/writer.h | 610 ---- src/Native/libcryptonight/Makefile | 11 +- src/Native/libcryptonight/common/xmrig.h | 109 - src/Native/libcryptonight/crypto/Asm.cpp | 100 - .../libcryptonight/crypto/CryptoNight_test.h | 237 -- .../crypto/asm/cnv2_main_loop.asm | 25 - .../crypto/asm/win64/cnv2_main_loop.S | 21 - src/Native/libcryptonight/exports.cpp | 235 +- .../libcryptonight/libcryptonight.vcxproj | 84 +- .../{ => xmrig}/3rdparty/aligned_malloc.h | 0 src/Native/libcryptonight/xmrig/Mem.cpp | 77 + src/Native/libcryptonight/xmrig/Mem.h | 78 + src/Native/libcryptonight/xmrig/Mem_unix.cpp | 113 + src/Native/libcryptonight/xmrig/Mem_win.cpp | 203 ++ .../xmrig/common/cpu/BasicCpuInfo.cpp | 146 + .../xmrig/common/cpu/BasicCpuInfo.h | 73 + .../xmrig/common/cpu/BasicCpuInfo_arm.cpp | 58 + .../libcryptonight/xmrig/common/cpu/Cpu.cpp | 57 + .../CryptoNight.h => xmrig/common/cpu/Cpu.h} | 25 +- .../{ => xmrig}/common/crypto/keccak.cpp | 8 +- .../{ => xmrig}/common/crypto/keccak.h | 0 .../xmrig/common/interfaces/ICpuInfo.h | 63 + .../{ => xmrig}/common/utils/mm_malloc.h | 0 .../libcryptonight/xmrig/common/xmrig.h | 118 + .../libcryptonight/xmrig/crypto/CryptoNight.h | 59 + .../{ => xmrig}/crypto/CryptoNight_arm.h | 214 +- .../crypto/CryptoNight_constants.h | 58 +- .../{ => xmrig}/crypto/CryptoNight_monero.h | 54 +- .../{ => xmrig}/crypto/CryptoNight_x86.h | 415 ++- .../xmrig/crypto/CryptonightR_gen.cpp | 162 ++ .../{ => xmrig}/crypto/SSE2NEON.h | 0 .../xmrig/crypto/asm/CryptonightR_template.S | 1593 ++++++++++ .../xmrig/crypto/asm/CryptonightR_template.h | 1063 +++++++ .../crypto/asm/CryptonightR_template.inc | 529 ++++ .../crypto/asm/CryptonightWOW_template.inc | 486 ++++ .../cnv2_double_main_loop_sandybridge.inc | 2 +- .../asm/cn2/cnv2_main_loop_bulldozer.inc | 180 ++ .../asm/cn2}/cnv2_main_loop_ivybridge.inc | 2 +- .../crypto/asm/cn2}/cnv2_main_loop_ryzen.inc | 2 +- .../crypto/asm/cn_main_loop.S} | 31 +- .../crypto/asm/win64/CryptonightR_template.S | 1593 ++++++++++ .../asm/win64/CryptonightR_template.asm | 1583 ++++++++++ .../crypto/asm/win64/CryptonightR_template.h | 1063 +++++++ .../asm/win64/CryptonightR_template.inc | 529 ++++ .../asm/win64/CryptonightR_template_win.inc | 529 ++++ .../asm/win64/CryptonightWOW_template.inc | 486 ++++ .../asm/win64/CryptonightWOW_template_win.inc | 486 ++++ .../cnv2_double_main_loop_sandybridge.inc | 2 +- .../win64/cn2/cnv2_main_loop_bulldozer.inc | 180 ++ .../win64/cn2}/cnv2_main_loop_ivybridge.inc | 2 +- .../asm/win64/cn2}/cnv2_main_loop_ryzen.inc | 2 +- .../xmrig/crypto/asm/win64/cn_main_loop.S | 31 + .../crypto/asm/win64/cn_main_loop.asm} | 17 +- .../{ => xmrig}/crypto/c_blake256.c | 0 .../{ => xmrig}/crypto/c_blake256.h | 8 - .../{ => xmrig}/crypto/c_groestl.c | 0 .../{ => xmrig}/crypto/c_groestl.h | 14 +- .../libcryptonight/{ => xmrig}/crypto/c_jh.c | 0 .../libcryptonight/{ => xmrig}/crypto/c_jh.h | 8 - .../{ => xmrig}/crypto/c_skein.c | 40 +- .../{ => xmrig}/crypto/c_skein.h | 14 +- .../xmrig/crypto/cn_gpu_arm.cpp | 240 ++ .../xmrig/crypto/cn_gpu_avx.cpp | 203 ++ .../xmrig/crypto/cn_gpu_ssse3.cpp | 210 ++ .../{ => xmrig}/crypto/groestl_tables.h | 0 .../libcryptonight/{ => xmrig}/crypto/hash.h | 0 .../{ => xmrig}/crypto/skein_port.h | 0 .../{ => xmrig}/crypto/soft_aes.h | 0 .../xmrig/crypto/variant4_random_math.h | 448 +++ src/Native/libcryptonight/xmrig/extra.cpp | 119 + .../{crypto/Asm.h => xmrig/extra.h} | 33 +- src/Native/libcryptonote/Makefile | 2 +- src/Native/libcryptonote/Makefile.MSys2 | 2 +- src/Native/libcryptonote/exports.cpp | 12 - .../libcryptonote/libcryptonote.vcxproj | 1 - .../libcryptonote.vcxproj.filters | 9 +- 117 files changed, 13758 insertions(+), 16072 deletions(-) delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/allocators.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/document.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/encodedstream.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/encodings.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/error/en.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/error/error.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/filereadstream.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/filewritestream.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/fwd.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/internal/biginteger.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/internal/diyfp.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/internal/dtoa.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/internal/ieee754.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/internal/itoa.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/internal/meta.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/internal/pow10.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/internal/regex.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/internal/stack.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/internal/strfunc.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/internal/strtod.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/internal/swap.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/istreamwrapper.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/memorybuffer.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/memorystream.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/msinttypes/inttypes.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/msinttypes/stdint.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/ostreamwrapper.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/pointer.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/prettywriter.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/rapidjson.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/reader.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/schema.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/stream.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/stringbuffer.h delete mode 100644 src/Native/libcryptonight/3rdparty/rapidjson/writer.h delete mode 100644 src/Native/libcryptonight/common/xmrig.h delete mode 100644 src/Native/libcryptonight/crypto/Asm.cpp delete mode 100644 src/Native/libcryptonight/crypto/CryptoNight_test.h delete mode 100644 src/Native/libcryptonight/crypto/asm/cnv2_main_loop.asm delete mode 100644 src/Native/libcryptonight/crypto/asm/win64/cnv2_main_loop.S rename src/Native/libcryptonight/{ => xmrig}/3rdparty/aligned_malloc.h (100%) create mode 100644 src/Native/libcryptonight/xmrig/Mem.cpp create mode 100644 src/Native/libcryptonight/xmrig/Mem.h create mode 100644 src/Native/libcryptonight/xmrig/Mem_unix.cpp create mode 100644 src/Native/libcryptonight/xmrig/Mem_win.cpp create mode 100644 src/Native/libcryptonight/xmrig/common/cpu/BasicCpuInfo.cpp create mode 100644 src/Native/libcryptonight/xmrig/common/cpu/BasicCpuInfo.h create mode 100644 src/Native/libcryptonight/xmrig/common/cpu/BasicCpuInfo_arm.cpp create mode 100644 src/Native/libcryptonight/xmrig/common/cpu/Cpu.cpp rename src/Native/libcryptonight/{crypto/CryptoNight.h => xmrig/common/cpu/Cpu.h} (80%) rename src/Native/libcryptonight/{ => xmrig}/common/crypto/keccak.cpp (98%) rename src/Native/libcryptonight/{ => xmrig}/common/crypto/keccak.h (100%) create mode 100644 src/Native/libcryptonight/xmrig/common/interfaces/ICpuInfo.h rename src/Native/libcryptonight/{ => xmrig}/common/utils/mm_malloc.h (100%) create mode 100644 src/Native/libcryptonight/xmrig/common/xmrig.h create mode 100644 src/Native/libcryptonight/xmrig/crypto/CryptoNight.h rename src/Native/libcryptonight/{ => xmrig}/crypto/CryptoNight_arm.h (79%) rename src/Native/libcryptonight/{ => xmrig}/crypto/CryptoNight_constants.h (69%) rename src/Native/libcryptonight/{ => xmrig}/crypto/CryptoNight_monero.h (78%) rename src/Native/libcryptonight/{ => xmrig}/crypto/CryptoNight_x86.h (73%) create mode 100644 src/Native/libcryptonight/xmrig/crypto/CryptonightR_gen.cpp rename src/Native/libcryptonight/{ => xmrig}/crypto/SSE2NEON.h (100%) create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.S create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.h create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_template.inc rename src/Native/libcryptonight/{crypto/asm => xmrig/crypto/asm/cn2}/cnv2_double_main_loop_sandybridge.inc (99%) create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_main_loop_bulldozer.inc rename src/Native/libcryptonight/{crypto/asm => xmrig/crypto/asm/cn2}/cnv2_main_loop_ivybridge.inc (99%) rename src/Native/libcryptonight/{crypto/asm => xmrig/crypto/asm/cn2}/cnv2_main_loop_ryzen.inc (99%) rename src/Native/libcryptonight/{crypto/asm/cnv2_main_loop.S => xmrig/crypto/asm/cn_main_loop.S} (51%) create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.S create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.asm create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.h create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template_win.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightWOW_template.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightWOW_template_win.inc rename src/Native/libcryptonight/{crypto/asm/win64 => xmrig/crypto/asm/win64/cn2}/cnv2_double_main_loop_sandybridge.inc (99%) create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_main_loop_bulldozer.inc rename src/Native/libcryptonight/{crypto/asm/win64 => xmrig/crypto/asm/win64/cn2}/cnv2_main_loop_ivybridge.inc (99%) rename src/Native/libcryptonight/{crypto/asm/win64 => xmrig/crypto/asm/win64/cn2}/cnv2_main_loop_ryzen.inc (99%) create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.S rename src/Native/libcryptonight/{crypto/asm/win64/cnv2_main_loop.asm => xmrig/crypto/asm/win64/cn_main_loop.asm} (54%) rename src/Native/libcryptonight/{ => xmrig}/crypto/c_blake256.c (100%) rename src/Native/libcryptonight/{ => xmrig}/crypto/c_blake256.h (94%) rename src/Native/libcryptonight/{ => xmrig}/crypto/c_groestl.c (100%) rename src/Native/libcryptonight/{ => xmrig}/crypto/c_groestl.h (89%) rename src/Native/libcryptonight/{ => xmrig}/crypto/c_jh.c (100%) rename src/Native/libcryptonight/{ => xmrig}/crypto/c_jh.h (91%) rename src/Native/libcryptonight/{ => xmrig}/crypto/c_skein.c (97%) rename src/Native/libcryptonight/{ => xmrig}/crypto/c_skein.h (95%) create mode 100644 src/Native/libcryptonight/xmrig/crypto/cn_gpu_arm.cpp create mode 100644 src/Native/libcryptonight/xmrig/crypto/cn_gpu_avx.cpp create mode 100644 src/Native/libcryptonight/xmrig/crypto/cn_gpu_ssse3.cpp rename src/Native/libcryptonight/{ => xmrig}/crypto/groestl_tables.h (100%) rename src/Native/libcryptonight/{ => xmrig}/crypto/hash.h (100%) rename src/Native/libcryptonight/{ => xmrig}/crypto/skein_port.h (100%) rename src/Native/libcryptonight/{ => xmrig}/crypto/soft_aes.h (100%) create mode 100644 src/Native/libcryptonight/xmrig/crypto/variant4_random_math.h create mode 100644 src/Native/libcryptonight/xmrig/extra.cpp rename src/Native/libcryptonight/{crypto/Asm.h => xmrig/extra.h} (65%) diff --git a/libs/runtimes/win-x64/libcryptonight.dll b/libs/runtimes/win-x64/libcryptonight.dll index 12b2504e79ced8088692608867cf7ebc30e95be8..4bdb9c811397312a38da9228bf9acde062f4047c 100644 GIT binary patch delta 91319 zcmce93w#sB_J5K#P@rK`AW|NM04)|OSg1&`pot`~krYu1q!y$Kq6kWrR#3og4ZRYU zD7q?meW4c>6%@sbyp)u_DUSjwMG=bl*jkjzvj~#^_sk?|%R|w>_t(!S-I+NvXU?2C zbIzH^&gOm|k-I2zajuj+{O*XkJtH%MzdMIT+>wR&ox_AXve~o69btI(9ogcJX!eY_ z<3aWe!VPykiul}~hKyr)9=%n6$8`1-?s%L%Bk!2Up2suzvo(v~K6TQ4sPnoEP2g{o zU89-&uLzA{&&=_`v^q_9b1PkIqsFJzXvX7*zoM>MB}v;;ml>vHXa@|a{z#`;4#@nE zb((mBTf#Kel(SB!Y1ft#0)L~zG;>>NG}SNYG+EDd>vYwqB|43UqvSa%wVL~M&vfgk z7l?)W{oDZ@57Vt%DzjZdH)E~P*U>?o<+(?UB~P1i$l-{B9!qKrCFscDBCpDC}RXlnsMV;HY__eDiBC#Kn5X%mNz{5KUbBi~hceyfz| zy0$>GHB_Kp`9;^UHMLZO7Bd=tQ?3fz@@%+X5S$6mD#E!7Bbln#%;Q-hpIzJi(#xrel# z37;>xH4=r8<{7gekE(UeSzey0R-b!V(t1*>7ECmVp5d+Wy9&Q9`1QoEFMikKcO!no zP+pDctkrmik4h?MbypEu;SE#*3;?_9!{=rvm9ImCbCGPXT!*IS0+v)xdB*G)j4VF@ z=(`|5Vvsk4sNt;%PQ~;M&=9ao00>OT+LzbJ5JnBZF;|MzWDiU7mDu-dlFErBH1~5+ z2G3ITFXrhqIZ-JF_G|$rQHRt<1M)OMBq7DX0?h#e!C>u>Pxk0E>fL&??b#Mmcq!p zo@!R#cOd4`E0yR)ICs-?WBE@q~%_zMM{?XJ~{dkBHttqeorUpF`Y5=8VGD zqCC{d;4G?qc6ZnCr`KyV%AvbEg(a`jDgL`3GH==gzQ}t-uQS%HcKw1Pi(*$3v%s9! zBDBilNu8wyD?us=?)+F9!a}_M{l|5hB%cs(_%8wuxk~6|i?ukt;Xn|Ai}Eg^mos)0 z!;P%(A}i&~43sBe7Scar>GNZAdC@g2x+r!riyA(DT&E;Vjx}%pp%I~@R8A;SLxlR8 zYn2(3W4f$(FGOf1$2Jn!l6Iq(F~IZgJs@rI#*?Vo)0?eF+Q zb;PT4ft;8@h^UUp=7{GNRU?|gx{zc<*8l!)ph{b;@whOfrPCYJ#;Max5oVY+(G=pV%r(IgG;X^Ju(Yx6q7{ifLU z)Va1;Gt>q3efy-{yxS7a`u!xn<|#r~n+B+i8qIn$@TmH}TF8yGL1PKvM2j%E*HI&Y z)Z#Z)LdBH2>k)5_pIGWft2KW72}YJGdKZ8&)awSz@sR82Ar}f!?g-?hp)(3ivrOb| zyJQ0;w9rB=wD1UC;1^Y~kK0!m|3NR)yqvl@e8ZDF#{)LjpAi`J`{AU?6dh9rBnstnItaY5| zT^YNy9xcv0avyX7ge>mufRN>nf|i%_EAc;7J|lXZv6fW1PLz*<3U|Fhcye7cjmGKi zbL0oV-zv|~4>xNx4k@hIU+t6&t@2(`-l19_BAiM!dI1EfZ*-vN^Ho4e;xx)BZzPa< ze-}z0k!;SLg3))KG9Ipk>Ez7G|_dR<_;OsbjJz7Z6l4Qtq5Q(i@qaDyKD%NcDy{R}M|< zBpuP_EEZ+Cn&H}`J`_thE7YmepkLO8rOGAl>aY!EfLi^}6&o{knwk$_T|_yb8sbDl zEDki650@S4v6dQ5%~OAn;Sjusng@^}z$Xce`egaOM-6D#G}w=Z{y*|ylV+v1M`z!60t}o4 zJPp~3n`Y~YY<^Q#Ir621@<}95uds|vXp&9|T`d~H7$(YYAN3pwlwcfT6r!|(aj02{ zau^X!6r!wV#4U&?B0dUn3*woGQ}!&xGexf_7bu{I*dxkOCm7|$ltQ@N%P1rnT77OBuh=ZEppvIDk zIEsm&W_YGx%*|!B+?pjA7jQD3%#~Qu(-al+N|)iGzJA~TvO=oQm`fE2QK%O63sFx} z6x9d=MSlsJ4D$cE)>5sFDo0FeQn{FSo=lJMg#UNHe}e`tS5mop`fAd9hViA) zV6xUf%GfZX=KHdntA}U8XVa^j=A#V_!+lj8MJv=X_fnl@&5#Ve|^nlMS3! zvoJODE5wPKeArUXJ%cEJO4>4~g_yFQif3;Yp)(opx?WG%xY1_`4=&RL%qTPp>f1;K zq}r!KBwe6!Z$J+z zKD&v^R;XW2f`qRPgM5v@QKx|gbjrm6BiOFMDHBOVFegz&ocj;FA)>s9afZ6X@EZ{3 z6%p$u1ie|2yxCU*OoUr1+hVi8Hn2~MO$6t_w!7V`HoG5qm*Wxvp3PVoWSv9as$LH- zlDwg0s^pzBh`5Wy!b|5}2*C~Io%ct1rLF1#bW14nZNbbz_lZjb`P6X9w>ac_rwq>o zep#7S-laYZCDN#eCXFLYX4*muDdb=D9Zz{G)JM>zoWth^2RK~1K`JAWhXX$`!{LuD z2-IpBI}XxE90%h{Uk*v187Uw^lz$c7za`APD#_>YXdE6(1b#;RqHEq^;`MUuD3-H> z=vf&nA_z%ydX}?3A~8#*B#2pJgaq-~Ii*P>60vjv$?_3lkTNrg++r$_^hl4O2X_R6 zKIoVPJ-C_3ISn3Ml9)8@G9Dae5m3hXbIK*;xD{KKK{GzQ_alr{;?TR9K@KIRgg8`& z>{dUQ!9>=S0R1v=k0|pdiZX9C$s+NI#AF{dHe`_)Iq}Xy#hTMr3bFN*fBz5J3a)OR zOpOY;cxLD}a5c?`=3JJo`=h8#Q^)uU*sAQ!Dw+Z(ig@_%JA*tl5Bf)VSbhSCFT=yP zm;P^g_yLAYBOV&D7WSt++y?Ot@-V0juY`wJ&nUe2SrcdCLJV0xRE-1w5hkubc6lZ) z!8&GO3FObm_sYLGz9EROVN^9@qNc?aFmV&4HOR!jFus+6*(H+1bVG$Y>y983f4}Y@ zVd7hLjhWa)K{wKulK#o({sKe)s=@?ApT-bt#L&ge7Yyl3r}2;7wqW`{ML1fBC4ieW$E|`C-rFg6j(2(^QAJvO1QrwH z9daRZex>+kT`xKMX`M-x4)-rwA^%>iPc^dL@fM=DLiLRevVK@U#`;vbG~^vMwm9v7 zMuEH{;ukri6Yu0c5ceVi3~k`&uZzLY8~O4lANxUuS~95O5JMjtNYP6$^u7ose%7_E z$e6M3?6$#e? zrRQblJ2+(KiY!2>fGd(qL3k&#*)!k|2b^J{*T>9(QD>x6GeTTgHh`%vA0&yS%0e8e zr1FhClSNpi5(kkD{j@>Ep#R~Pz&mluKU~r~sly5qeqC)!>qoEC-Emm4Jz5~m8celU zsKV$V6QA#M(YO=hIj!U(lS@o4au$0A+6Fg;+DdK;HJ{uR@}@{=h>7H;^sT`&uZXw| zH-%(Hl#9eQlOOvgT*8WOG|5e)1w2|rg$!wkzp}pjfsus(h~Qsjc;f@EJx zGZYtAcRA#IhE7Att3|IXywtt|7+8sBC}HzX?MkpRPwGlxoX?Z$qZoFYQj1FMRhV*V zO6~jUA(q;qi174`vCx9^C|Z~ad3H%Y)Hqr6re=yByAkWi9(%NP-9nb%ZbmFV>6FKg zwG_LGUmbq+_+bMo0!z}Fgcr~Ih%h{-hrvIkKo*)z&+Nc+cHlXeJ?**lP`8}NvVf0B z60v(^Pqrt0J;h@mY)|@bN~t|XtM%Bc?Toy58}gWGs-B36+2GnpOe-K7hzeab?s>*O zR@pcAD)+p0edbC=_q^ynb6dLSb?zg0Y3AuZV-dW=5U~1vHWa^R2wNQRCLzh;wQEIp zz4?)=tn196T=arP-c*aa?pck-p7irDVeRBT7KgvsF09>V%{|oIntMi{Gx)N_@}5Qe zQBL&QEsn5a6toFzBdoqND0oO~%`FJ4?Fbaj9@bkw)Yl3K>SpQf{mW~^0XvUMKDTW?=yEP*aQBF@`MF|+lW!D(OzqFYMU*kN_aXBgY9P7`RP(y*gmTp zU| zMB9SVzuV-r*ukK4w@t8B+7^sBXT#pqVB3O8=SyiUYiu`^<)j4aTwpUyf+&VF3GT!t zSPF^o*{6}4Iv(-}N+HJX;&2a^2{3FJi;CE&65WLnY-F)<=y0DKJg+l*5qR57JAysVj~#8#$*3N8z$Y9Y2*fg^)M_G|e!c+&KnEK*((8K#Dn zxCw=821*n4YfineN~^W3S-x~r3mBC@vubZ-U1-%-*pT8)4`*i0`l*@fh7gS+i#HcA zX4e|ov;~2*vQj%unl!L!rFI{Mj!Q6Xuwq3N`6JslVR3N1BFTqNWLA$^G-Jr3MF%XM z8CvX*EE_xW0vwst&k_QYY53uJAG2UEb%Ez4EuA{#$15;xq!AlTTXJnH8fi2>lcy}^ zR;_?rHEC`WtCj*%m{seKfYo1M1D>E&>x!hyny2JB7g@C;Yi>1+Q~e)VHLb+UHL+?M ztFImft6|lA%&OIsRa?!hT0OIBKC)`QfK{{np;e0l1N4eez^R>P2)vba!Ry zq>2k{TF8~U$f}jYsyTvI4J)N&)kH_wuAo(`yh5ucoeEgB0*CudW2=^n){<4LXU%SG z)uJ#~np!m){7tOdjti~Yf+kk&wg#&vz0%04xh`YX%9vGyF~fQ=GiF22F@qK|UFc&i z`A(69ne3L03|M316|!B=&2D15q{hZ8`4Yw}xxsi{O@oNBqh@mxYcXWAyi@SlJgDqsvXPXi^!{ z4SBp=6Jzv0o?=N&=U9I*#o8J$M}KjOwd7)R)Od;|HJxMqpHH!*rgNnNj&awW_r&veiP^&xev69uYmri+a%}Xus)JpEBP-$KfO%ttrC6+P6DetG_Ai0z*^qPs;ey=%I zcA?kMGW;8{4*y24z`u;8_%~?*{=G*Flz6V8=^dUMU3iM#>DWzoe_vhv_>3XzBXk-( z2Sm|xuCW7t-HW7xxyF7)*11Ma@%b4;W^s^7;92`zji(b!-sE@C;S!wM(G;OXca)7N zUY=f5d@kKr{IY9X@rm@ZqJr$Sy+sAn#~vs?7d0WXcvAqpZG2O33BYzu@i|vv@wqf< zCyI^zrubvm=P2shQv98(x~O2h%ZGpIRIdC2)cey>KE14X`S_wH5QfzpzzU?}UAs8K zb5XD4qIY>U-?`M{&s`-&1!+J*$fYKPQ#z;u?B(&r7o)c{pigUrepw^*jQGOh{pmXx z`UdRd(~F9%)5o4?*f(+Fi%+CUrk>4p8iJe(&>ZP11z$K@f-F%%n9EoEc>`7yH63Y& zj+{QWj}1?vocG4^@!N@V%22^G#P#4Ah~&<$V!~d0Vr)z*rAk4j7w>oJi07Ow0R%Ef z5OY|Mn)at_S$7BelPZ|T;if{s1LR-Bx|LP%GnG2x(ihW{b6$%!vP3PT=c z`kZyHuXs~K8(MI<{w@Z08H)-Ay9$C$SQMyXGOwW;G`3*a_q$4hOekY{#tt#l^PI5_ zH4juL#N(ZxgFt|%ka2g3TUeTs9V6>y@bE8^9 zHd4*SCtPDJ)N2Qd3MRXX0B~)EUth>DS@W3aV1pi5m!E! zq`9txRC+rV+(XFFUf03m@9xBSa3Oz`rnr7qsyCzFD#XvM!@oJzb|HRfCH{@@;os=h z_?NK^|0XTQziGMnw}yOeJU3?I>5vceiO9BXIP{8FAzTrnCkwAv%#J3dvkdOJ&?`$7 zdd;q~3B4?3_$RI-U6RRkNxf13mJS_$cwTf|WSCB)Ek=qhkfQ$z0j=B*OCQB&W(-LM ze6z*}X3dV*n-Rg&5JAs#QTbpZ+K!UU=&{sQt~5E34Q&{`is<_96aX#-`< z0m!>ZAma4KU>QpQk{g7487w1Z20$+aK~5?p7W@*C_k#}yx`~)vy~z z8%b|gBPp;I0L3}dTzoF08EcXTs^;*#W$UnO%;Km6oMNbg%<_)OY{IK4f45+tP(g_a$dy-l;xy;geoX_f3{O+!ge$P~>RTfZAEzg4zb!s=^y}i^@k6d$T9~A4TFNFApRC;i!|OFu;opz$DgOEB zeyGalmr?xtqwrjeulT?s$YuUA(%ZiuZH92OqQmzzD~uv-kqaorwuI4`w~*kQFWZ;M z;+1>^4r)c}R4TsJ+@xDc%~Bqu2FE}(k%2KV?Zlrjco{MViv`92l~w!mf)cBo#=u2g zbGeddj{nUneJDs>y5d|zmrD8!77Hj1DB5X(cqTC&{Id|FnF1w=M*z(Ujf{|G3$hTc z$Y+G}wnAZgz114dD{E82Sy`#EK!yr8QnXZ9jkrX~D=N72SQB1dOfKrrUxq4RR)by4 z=v7}pNn+OHXB(Jh=tmJKS|*@D%tNLQ&k{4*`Kddqn z1&MFsZw-9YpFKm71{rHb!1EdKo+Tsqt}Y=`Oz47g#q@1}=petmxtHPBH+7Ag-N^k4 zA#325)RbY%ue@Z_g46zHK}qe8l3>G+-Qqd9*xQ=Do zwy~o9^=LUXm`O7Hnyfn;AN`SN^ zxwTsp>Hn5)pskYms8)o&g~}XOXk{9^D(%Ojg4yw9#dYc1iV9qJ9xDDVqoBCvXl3!4 ztgkvj_hVL&RS{ME>(PqhGmq~mmggeQqeGq@x`>35sh|X2R~;2DS8D- znjdRKLST)>*iuL@5R8dzwMB>@l73RF!CJ~t%z%tKAsvS@Tm^`aSU1Hc%rLwM42X?h zK`~Pd&l^~g!ITNpCH%+E9RA~dE1M91(gqwte34x+4x%zKElx>V)E&QVPZb4gQ1B<>4GQ~^{+%$sKyd8MhCbSoXg9)y^c;G})IwrYkC_dKo;c>>ftw3A>l7+E` z%_p=PP|YZgFQ;asyS8yglpz%<;7L3Vw2eob(hNr_zeLoIHB9E%PBZT8L_Nrvrr&`a zfa-^FXeH{}g+`$EG*;Ix@SU2GUL?f-Cb({((&_cAVMZanSV$YPi1Ljcq6Y#7tP|1( z%w}l=em#b?cxeY1#p%~FoTi_Up6cyHEg64^dLX?wh!x1E z9$?~jbOT0*;M!u9(0y2z$XJTEA$5Wg_YMGFf?qjON325tvK&8Y0k{M)np1@Y2uS?s z6~KZpgf4z)8HoTDil3<>zu-dEY5G`R_@G(zrp0EFK|{vWT&s|A76q0u3nwBMw@ygL>9LI8Z9+z!&}-gmp;r#kIuA$A z0*XnRi+(^j3#qwNusd800>UX4xTXXou_}qAEUFKAasyTs zlp!UTVFoM>FPw585XTyk7^r6y(}n8&L5$KrhB7*c^2#xSKFq&}R8Al};>|e2sVu?5 z1oXg|#nfi)8f$z3b#p1f&m>e? zR7qpZnoDAq{t47?VXfqE5-pKLveAEOs+~Yhqr-NDdWVgUnpzqi@pb5))=0%bIfX8& z6f$zE!6UAqiCIlm59=SsHenoWtBV}QF&eD@Lg1#@g&FlAVodH7t1#0qu)e`-Oc@0f zuhQbxCfIqX9%QVo2RZPN;_a*9!XBmAmMOx_Gp+Hj-hh7xbyI{|yeNegAq2QDJBqTN z;ra3QR4LFNEyP)*W`Y#2Kl@WiuwbjcLAB>dz(CJtHLRnC7JcZ~HgO*4@eV7{x2VFfpz;u(V@j(US@J+vq=zQ>b? zl?^`*%9M(k(Z73t#Qqoc7J7<0iFi#-$RssK0gE~Yq+HwuEE6%Up&?X+D!rgBfsO?# z*0G!h)sH2I09L6{&;I|SeJ6l6)P_se4k{bfN$Y=&nsJFHsH1_FhCs|M;1`v~2$;Y- z1S25kyB{v{!!Q#d)juW|eRC4vP#xUp5SyqA&=++Q`r+{RAqCX98_0qbv$hBslZ$JUIkmJyBZIl8;}+pK2^jZDG_}%hUW~9AE>Hvh_tJ;GojA10i&+{P}Z>i4ML5iQw#x}K82Xqp$?+6(y zpM)1IVGgC=Rxkrz^`4h2exsy-#a|HdP2@1cf~7BW=FkVtJ{busKze=e^- zV5!(R1|J$*D!Do&^i4D*jEIj7HFf<@m*W?~vnXRoz%eJFcCm^j44pt{Fo|Gp4c8?! zo+kZGw1kz~!%#B{8T0tSQwJKR&7arr0dgpsbJ?2^;}et;_hnJ$i}9GnJ$ak14I$` ziJoBNRufWCfaXf*9cFEi0XD6w zWJU))vjy?Sw&k8&Se#vCh-i}JJmMjP%2L6)aA@+v)EF@ND#$(v#2dbI;qv71WpH6lF3r)-zsBL}> znyKLU<30c(L zNpx{Q2fmKnk8Y&7lnD%G({I@Yib$<6E~fG?p}dI5 zcYu-1)aze!wMZikqwHoxZCL-O~Ss`@Ytgm<NjK8$vdJsX@BcTo;)8pY88ckJM2axHh3$>8~ z)DwSUR7e)}>2EK^Ji^6>2Gwvum#_*^4_nd*C?l$w27e>c)d7Ew8U0TlGfMK_zEad* zANpsAmM*3`52&es9<3s)1A|0e1p72r-ySKLi(osnI%t}%W0?Zeo{&X?alv+{3){8v zhBn9nb9EqKaA>kai*?L6)f=$?I?jiz-y#_ccF>L{9YaYLY9<*kvRiysglvaVFkrES zqxNdDSc#C1*Y<+2w77Njz-H*3agQSeYRWLOD`^ge^}wuMoq&jLC@=Vu8kV&s3ULY5 zJYEvo^XL2h{h`%pv!C|g{%o_KHUnu{>rc-+TSn8BHe>lK9Ua$Us}1)9e~a_axKN`m z_iQs^{tQ$n;#!DNxc2;3E59Nl(<$$96#Rs1=_|y78Y5opu5fzhVm7iC3|@=7W^ipp z;2bcnB@ygp!df_V47e3Byp)S%B-G$q6rHfvXA|u8c#Sv$_q|vJTd`HjtqJp0>#Qw{ zebr&MmVlkn&a&83O0rXcztk?*IppUGH4oFp^eYP^@Dvk%5^>LJXHg!A3p44?;_N)o z?G49w5SoMX7c4mFo$?DxA7zciH5`Pa*7%rCGym(HcDXk=a&XgZ^Ae3!^!sozLUYlN zTP9c5MkB+;$fKJezX8Z|&uVj80)bdiYxcO#Iqpb^JuU6h!Zw;wbv`SR*mk%q|0?yXBqU z0mtvt;r1rz1c!XU=^gU$z2Hc~!N7%3`Crr3w}o^`HtwCBlFRs!LZdoMl)oemk)>+b zYrW%1sq{&mil)jZ9SNr-G5^%#QMeq^fqb}mDS^s{9guNlhhZn`NWezLfJw-1O(+!; zPU4!|q341{MEMIUQjarSC?X~t^qZ~|;Nue?Ku8(AMUIwE$EO(3+}UWTh27AF4<&R) zK6=kbToV=9K1}FvwHJ*%P9>v{bnG; zIt`BVSQC8CNj~*!TyLBQ2yw@2y77}WhfIUDx`VeWUEBB79#=-Te?}K`t8%FQHQKdn zT1U5Ssa?6Id-wNSY7ea0bqx;xcO9r4ymqkmt2LbyH)(aT1J-=iFC*Nzj2m*7n6MRJ z0-3sOjs5ynLfrJ&=s>ro;a+%r9>S@$Mqq?EWd|-&u5rk97?6rEtRqgs(j4Ad~|It%hU z6AI|Y;k<%nh=^g^)tdu_t(yr?PF$lbZ&#)1#EnwB5qU7OK3zr+ z+y_nAA0!#IjPQ28+6fUAo$@J1!7nWwQ%e|{FbuU4v7ow{Gpv5fl+e8j>=NP`L6~+HDjgj!=&m`p<|D`ct90iR zl*O43>lP*`;df2eg?Cr(zf0BK&|68nd-{^kJ7|qc?y*)l7ANb!Ux99Cx6UE7h`V-TVcRv6f;=;Uiz6nT0sPNVHr)1gF3O3ZfXo z3kg8)5e;L4Gz?&0LlF~p25gAjoD(3m3KGy91mN1~aC}|`Iw^cmkbtn?{}urbPQVve zYc!i#%To?Me4V`0kpK%#w?9}p1(GH^l2Z_A^)#<-ZsjyM{H3=9XxM9APb`8!fHnsP z4UXGT|F6WMxIbh}p^b3VSvXAngyfu4zg@sa?YfK!6Ak{l(~+ zUO@t;<1p}L3CM1}7*{S?^9F}AsXPwD84eqsDi^6X)Q>wo!XNGrW^lD|IPR>;-)S$ zbs!BUT*}^=rO`d&NxiqJxc>*qWG|suW{bFFFqcvSMvUEgj`LI7wk_G!LE9c~)IKZj zi1r$~LN2YcnmY(%qW}Zc8XTYnNq#;$vLOMbd4rn=h9&Nbcb8&h;^O)WwO<@n;Rg=_ z1ET`>l|pjGCiiuQpI2 z3~f=yg>8msfzayT<=5}S%~8VupVS-)ImVAm^$v+mshN@Zj9AS150SGU5-kgNs=tGQNxLlzcc|?dDZ=xG za$)VOyq*;;m4(auUKu?hRKCzu8wBx|%py;Wzb10G~(rfTCp^T7+wSOnTrl z##0tta}oj1DS3T+V%(c=GHGkRo_M{z7kaksdte5X0ZM~uu#~?cfzAUai*6r0YyCos z%lgCg@aWUtr5JYMEQq*}R;urdB&xPlACC~Rp;X^L5LyQ=Ys6_jlA+#Iv@{%V9V2sYlPVuZVo1Dp`Q%FL=;T_2$bV?Mn4*sOd}TUQG~aP@t?QAi4bqW*gz;q6t!R^(x3qoMNd1t ztZC4_{h{)~+nqa3eV?k^SWmUG)i-%3?(p=R(%)CUe|vzg_xnoc6)~O9uA*FPC>N%9 z7_Z2h2}SNV)vQv+tQa6|Kn8r&!mpeAAsTAI_aUgQHC?Z6tYhd_|1GHdzpQUtiQdr> zN%#z2OVM*ngy7B(R=F4UmE@SRF--3et_<_Ug-7W?WlZ5K+?&^*4M( z%nayzO!m*f1dA#gB<+l}s zZjK{-Xox7Du7v!yrYPDo0hY~RB~kasEksG;nxP-!H7kglUi|=skq1vD=bc#X4CUYN zbl07GSNZIn_C1rJG+}j`s}Jg-!aAsDkDT{IH81bYlEeG^YMZMg`YLDN>3Qu4V1v1# zv^MINBo=9|I*?k6v(KO;9{qMCUfl?g+CNGe_3ky=MasN)JLr0^RF=MLma=+)9Lg~q z`WTfOLFYLPD=Jze^h2p}L#j|IE4e)bJ8*YS7;-!5TP&|ND*FU54z5){Y9w_C*|(|=IVeds1}5ALA- z%}*;j73xcU(e?0T;71$WZ)*o@)T^!q1?BlZQLt6ebQ#h~>onBoZ__Y3UDe5Vy2@Y1 zx|Rm_fK3ohcU;cfO6OJGbT7TE+_b7&WHPA17^(A{*1n}oUlpxe{+9BuRX6FTy`_|{ zO4Pk>P|mC}>+XF^>GXbAL$kLiGd2hD)u1<(;qUkF@N_oF_6}KqM{OH86y#Mk^P9@v zR(8C9)soHzZL3b+m`Oa-_zN;EqD+acbCd zK3J;XuW;<8`Y#pbn$?MYS0KS%7E!8Sf&gAw(s=aGBV;{QXwGiyE;E(0*q$jUQ?^LDOBY* z{YFVi`s2?M=S<-&xdJL?>swkB*w3L~aOf|@a0v^X9{tA*{22#-!ok%9X3$p|bQy=f z$f3JK&;<u2K$O5d#16CXuz87k-CB-wi>l z81z{Vl{s{I2)czqvpMtu4t+HQUCE$hIrP?N@FFz&X=w=j0s|*=a6ex7*$_0BK|6A2 zTMm6L1iha@&%MrCd~z{s@e3hn8iO9-(7hardQm^?;~N>+$HD74xS`^B27QA=U*gb3 zA=GUcbUug9(S;^1-)Zm4)R1AoM!?{R2D#dkC4a~$gB(1sQ} z8T1hjox!2ALu6ggpe_!*P2%9k2<*}K0F2ECZs6b~4$Te~ZpjLF=1>!dJ`#eS_z$uA z{A;Ymr1Ff_}uH%Q^HF4jmhUzRaNi;!uf0 z#Srvg40<1j-bGN4{xPJ%eRfOyRxq+GaI{k205C~^Bl2XoBHIE_=tVTvZwfy)oAV`DQk0fpKGNBJM&=9gb>qehK)GC47$UE>dcK zGf3_-f1OaE{}G-eW`&Ouids+-LV>TI!D(rV0u~YeC+NHFRhW591vV@bFuhHHb%Y-0 z?J?!E{?tzaV(96lEzIzi1?<>5G)bKS|0oOvl+~;6j=Y6fgjN@-`+F)~KD=Icq`5No z!}-Z)pyM>zAj?pPkhA-r`$~Rj>DXzOue1_JA9V4WLSjO;c1riHTe^!cJL?QS!hL%uH}XUYx@#m<2g+SoWwBT=We0a~2>@!D zr!q}A0p7~%|3)IbdHnEw#jmrYPK8C}=+X3?=B4&(jpaqHO}1Cz_4sOeOp%=G^P6U& zgwu)Qxu*SyFmiDprAZjxnsj(WLu9WY1H=J zDQg@jfx50QKCr1iqbyw;*WqYBbk}ZmGD;B&_vmk@rg-$DUse)6>C}4)l>iSSRS_86hB1iy109IQ z$$A44kiE;x%BW47Z)RQZsDJ}ddt2zk-@s=e56l}(?ym6gYa z=zM#X+G8EM)#LmqTl>PQF{H|Gl7WLOgPdFaCcC0^Ti^D+$~VC`r5kHxFB|6mUek6Y z(URFbp4t{_lHu{2QaFZMUDDUs<^6dJW<%(De9g1e@#OqdK2TBH1$reIp&n=fX2Zi( zlx4@;cl+=Okn}YP#Vycv4DzZ%QsT?*@09h=KA}_{?{Y1*rnV2-GZoou*CCLJfK}eI z-hxiXep*7AxM!y$>9-M2ZbH+QZX2$R+P|EJkJGEKKmcusRPNdkEsZ96NiRX;Z-)L2 zX)$>pr2Q3SWpaaJ9$sws^WesMEEU4N0#T8{!YvyidWs?9Mj=M`2v}qQv928bpLr;dE`?| z+FE>zVyL_*Z=4m1DXiRoXc+>V@p~P=5Aaj*tHV!oGqf0fD-gEeISRi@gfsDs$1e-N z#rPFlwQE{_cAHk$Z=Nz?^CLQ&cg+`@muuUS|AN*UME9Y3QFhd;Z-pzJw@hs_yfao( z+2?I*@#(QLRSHvUSNLty?-uHPk-=Ee6Ar4eN|!D}2M;CVz{4mb~w} zhDC&_H=(FauC(F1ptRxbK4i4vP|0T+a0nj?b#INZ_b9;`lU?#wcX@amcImLBvK1n4 zT~A||a_Fo*3Xp-)HqwSI<&?D69)&#PXS8@K?-Dlr)V2pcAj9%))?@;GkJ9Y!Lo{ai zA{~ZkEO;2KDWy3=-d39H);71c`m$En>Pvh*&611U?w>5#G1k1Fd=hd-THU`{a@qiC zbZsOG!0V|EN34TgF0!7kv`Ia-SbOZZwJNlwY!T)!0|i#O3~eho6oxZ1@-EJ0uneIz ze441$L8-Q-u%Wg!(Nt?7kTtKGh_vR>TCbKGLIGX2zyo19Cgc=qTe&MNwaxM>sKrz) zcgX9rL45Z0rwT3E{a_vb(-ExcS)yM^$?$_L?!%jrya>sR(Se?m7>8?Ha_9^|?wU+Eod9|$b zTDi|&vhT2n%~mn7Uq$D6=u_mN43qd8Go=>>wv&hhM(C5PmNV=QOZyBN%Dg~w8^gnp847db0M4Oaz zrJ1^O3Cf*i-|C_hl$*;}MAFxHvCkn_soUBpr^*N3I0-%Cop_ZeS{+1c=xojP;J%vI z6Nqu3?MYbbb>T?C!X(l7X)Xl^OaV7UPs|KinYMM5@e35(hz&s?2Ab1RO2yWG12-+y zk_(3aN#(Uu;of6QY#!`Lg?e`v)Kdqe*8yjVlGT@(NMHqQUb6ahl#*1@!+ZxT#qxVh zV-QhYjWRi-lt(J!+N6TE?C>OCt*CZ^icxFgl~on7(bpmw9-0vkNcAC*Ms@BpDm4|; zbYgpD?6!Wln6QN>;>*gQAud(MJQU7LnJQr0lGa;uM2F`lhr2XFjY4T>*vZ=W2!)L` zQ2iaAW-YdZjsyFzg0gGdH9Ezh__y^K`6?jT$c0nf9GG*CP@#pC)*$a>TgXab7L;Nj z_Y}@JTg#;hXJgpHd?jmp`<{0pi%LfcA;c3XTt;Epz|zO_aB9A?YI{Nt+IeO}tv!s8 zT#vE#7MU721fkKUY~J3XM|>zBNg?IC|H6Dh*}ggdt?B7gNqY+{Na#!&9H;H9WFL!GqIY!BJv&uN-Z8nwb8{f4vOaFA^5%}=Ek1{SLF|kB zl#@F~V@Cn^WEwW)VFzm-dO#Vzv%fCsoHA!;tggd-%IiC0B@ZsOV!PXc3BCo#yJ_03 zVsZ^`vrRP|1GlTp0mMkI#(shsU%>L%tJNRiD?$TVXx~i#5JUrG?_DS$eqTHjcCTSq zE<`tti}5!U77-3kt2$98wFmG7Qi5|*Q^vhYr^=4fwarP!D%7v>@+>{~;PeDNrEB?9 zz&#DDD4&8RmDe~9U;!wI#<2GZOzPO`k`^mVIbAV+ijV~LHV+~!rc_|Mw+Dw8pwL!Q zx@`Dn0ciA5l5E%~A%aW;{eobc z;++OQpw-X=nxy6|q2}sDodpdPU@T+wk3fuN7Yt`M>u}D7I@74YO7;vLF+710lihMX z^NbfHw8Iv#zQq)*Rb=;OXCM3~<0DGn-7&_v@W7NteHynW;5ZU&PG{X0k1yG-)%K89 zKMqC+sGYXe_3u(F4w^ujv(VeaQ@+_AUwAW?sXZ$w-~%bBSTJ zKOYbbH4oyW&c{DmFEe~FkI0B@rS?o@m|o-YFzALvzv)mm5^2ulJ{z603)yo4R?jx0 z)VP@l2RoUvV|MyF@}qAHhEU`ciqyOZ-4v=ERYDk0jvZfMs{&iu+NGM^gE;|Fe*K-2 z5_zy^N;4wF8(9WK34|y}zZ}yUvcOgs4$p16y3iK+{D$8jR~|Un!SE4)f$|4uDzEM8 zYA8XsZKTeHvHrJGv8zw3MU>JVDYZq)tb#7l8|I@$Ijsew{zK>`ylG&KsJ&Hvw1u*& zpnK~m#vr^9KF+8PN>sinNKmHluGWcnDI@oEh`Vj8-w&@0dx%-qbxVO#Ev(`xsaP4U zL`CXHRm!40ojS%mL~8245yU*4;ILqg0^IPM3=b&OX%SkzSt5E@cq_Ep2<$=$;=*s6P-p^xoBO;VFpC{W&V8nO)?n1e{BM}!s#=qJ1C%Yf zNu+Rpz`G&bZ8MyHj2*U5+U+;J{2*gS_UE+*wHlQ1nKtb!1hy3h!&e>1P8kGg-GI`5 z({vOB6WgorQG00T^sDJ`Ny^m2SQ+tPnb75POyA!5WHT`$Q$GYF_O7w3@>xwlp%M zs_03@4_`j^n&!?^KB~G#x|1#YAXRo`skb#mT&k@hlBo`Ch}@_4Zit9#OhaUpYHWzi zR>MLOPcDtT<7^5;Re5}2h#y8=nXqq^)RlC+{PbdEf*<+}BqzH)L|F`Qpq2YkBh;>1 z9}l?aHI@yFeBgbB>Y}s;mIst67K-oSE2q8HyQ3*b71@^<*{~exSf_oSC03{pP*-EW zTQv}E0SRez2+40ccOPWH@F0rGRkUi=MQy{%GH)IGQT6_uhiga#WP<~lME6#|nv5K% zE@wj-n#tFWJ>&%&uBIH!(a*tm(^Mn!!EKkGfwNI7!pBtomMjt8{CAU&lkd;Iil$(FrUn@R-x>{=SV*buk*ZF?eK;ZYY*-0|)PPRv?F=X5 z2rNjwU&@(LJ4ZGwLIy_u97aU;eT~T92CXO??x!4#m5lt+$Om#h$9fwrWbILJW(A3Q z3#YyxtEqyhuTa}@>ffa0Idor((Cq$d^)uXULn{P$<%g|R`b`V&r3!y@1=&78ef27( z^6O~n8uSM~vfE@LAsaqJMn?N8Xe6-yi$=8L!`wjiGUaGseLnJm_GU!;3gUb=D@e3I zjGXA4Nk{Fg<;cGGOdrO2VgAEVf5hllL1)bjMEFF?Yxo&C)lnu|@9*tWp4;EI z^KavVi})@iyA3sn2YpNBg@aj1KgBYd6?^Gp0D2Pz^N-UYSh zJ*^C?9vL|VH^A|!a@$jiQhlwiXCI}g`Xk+)-zl>XjnLhepcEe(sH;DvoIlj#sy(># z47+!!G$BkmOS8cp>gH3*z;FBLGjXLBJG?yFmM zQgIxP)jfGqnQ?f~Sh|OdNVVa)8Qz`F;z)oHi zUiM<^{7C(Vr1HYVvSZ5m!<}{C-llZ^E?IY7Z)NOvlXX9pDVx6Qs9SrtQuSSYyZLvc z8!>%c6q`jR8bk>)Ul$Xryz~7vonFEPAR*oSA`MJ9O3`5Fm(!HG z@3Y%mN}2fO7}c>5x_|{ss8iMJkKKiFqaj9v zw0wi|-Cq^wkJsp&waQ~ZcE5c&uHbOT4T6WFai2Y()238Ub1cMQTTV;_n@sMrzvr|o z)wc~Le}QDVs|krD{^V3%NOnao=@zYRt7z5hbTf*TfoeD1;M@m&Co2fV9y<%)n6_RGg8Vj!P z;Hn8;06F!!L%x9vtjTf0UM&~_R35{6@`=6r#|W|4FzFUb)UTvOkKuVd)CK4Ycsws6 z?38^UX=xk9ulC3P68+Oi)UL+S-HQ)63tB?p&?Hw77eRI&L&flzb|K(pXA3uN&!~&82KNP_9SN|*p z-~#CL9#D#ZiPs&yTRHkmjIi`GD2C!xZ>kaVf;qP+osQ;r-UL5_3dg)h0Thn;Hw92Q z#-nUHdZX^Q*OhZe2kRmZD>u|-UDakB2=nMi+(llAfk%ejrTFTu)_p%#sj16s+jcB+ zOj4l^oT9v49gI61l<~h_ea*fxOq0Meo_5IRYs1(|!%p=MzGyZwlZ!I8&wZHurJS7^g%=$$-jngl z3>4<*jZ~&&$z83q?Ud=qdUm|qeZfYeZ$H~eynQI!NHp(f8;PrbAax6GJGhb9HH~T^ z^F$ko`)+3&i6`KksaNB5Xw)6pNcIaQyXn0?i|f91U3@$o@ly}Xa*IbjYNu2 zdti;gm8V9tjYRv+AgSp_Vt+!3e6*3+^Jcb@NUdQTiN9k{h;1aEK;SYPiN5``k=SlE zXkL%a8rpSRhA>SImHSR~)qOKs@to*1el>(DxGVQE!UV@dT}`eOs>kw41#?p{4S0@7 zB9{eW&F#UHvuw{WkI-Q1LDf9K(LDITvnQ{TMm8$5`!;gR8|^eYsFa?U8o*0kkB8a~ zm7`iz9~rE#StC4;F+2^%8wW8kP}`v-+a+v8STVC8TDqQw+^f6E*OD7{8aIG=+G)Ju zHri=yw+DIHPU98?_)eow`T1n$mKlM3g`=?1*k0*p z$$(){nU>v1>S@Sr8MJoRuwRVH1(xr;2FG}1-sx-NrZF$C=}za2TY<1)r&GN{*>O6$ z(|Jn8iCT~TbD(TkaEU9*P_*^EboY-`uBpFX_zKjd44IB8nQ-fndnPIm)yEnqq9}R< zPQ!Mzt6zrlX8jDE?+)dvGq*?2A4$~1$rqs#&uAZMg$X1!bVvR__P#u>s%m|Iufrf9 z2&gEc;89U=MkU3Ga~#7&MJ2_d1ObIaAO^)U4>=S?7G+^Zfvz~XoYuIbQd+oK?-uvwJCFh1% zw%@qE`rNqgh4q-x9K`u}Xt)$qwy#0$xk88gsabW#`KLoCCfx zPRHSI3`dvoCXYT3z4-Y@Wr5C&uhxHjVM6=sL~&2R5EF))5Ib*u?~5}#CE|}863U$D zC3Cg+0tRK{y31?nP3xb$*fk*kpzF-$y#B!Yk1h@xGZ%e{;db4q8zh2fyNw-&;db4q zXlUYBZ;UL#_TlZNvxO~qhfp6BY zxzugQj-lv9d1AX7`^0!~>_a@u1ivw#bqRO|YMgXK9)le&ZVl6Qv)3QK)WLFK;`*jb z;hyt9$El*jM>c7fcOAdWto2BpemF{9XF2et-nN&rc9FG<5a%lF2u|x}eSt|E z*7H2dMu*DuL4U?WEwtQGr~7)U{+2hp>BBtL2utKReW|CK(DKk&<5+3s9Q%ci7oPgf zb1mw6O-e%DcuQrN1(#)aZo+o1^-6=!7x_4oWev!+e$c#LhW7qswEyZn1I#>$_^Yn< zBMBuhwnO$aK@z}y>c|)cedk}Xt*UebJoWlgfvEnQ?sl{pcY z(WBk!VOmkJvk9)}vN&N{G>CPBoBoT>^bLNh>%b~gCocD1i4@c4Q|FVWE)+VU>r5&$ zZReez=_mbEmywU+0Ei!UePdx5mR_Xl)>3tVbAn;p${8oP+TqmX@w=(GmdDU07GBQC z&-5uRRaDS<_$y|sNa%#VJ~3avtEK95-Fuj@%b5hz-u7j8VxW?tGr*bMMbsZTE0M`K zMas=HWDP^s`{wIEwp4d|j2@!&Tm04Jq&MMmm|K+voVX6J7L5V-rdLdP2e4q%g#-fzgIYh1{Q_MqmUuay&pFp5F7UC);8)b%U?(7^=;t# zS)=rjwkpojYm|OtTQ$S-#Yp|dwkpE1Wu*RLTP&|XI#PGGRg1g!8Yz8I_(S}NKk_?H z?DLO_BYs(mzQt{`k1@1e4)GnS7lo+5T28Lf!`rFBt?onXU8}w+d-a>!sYk<{STr@( zeUHt;RGC?Nv$e%GE~qCga~dYK|Xs-d?Id-ClJI2tzg=&cA-3f7)Jk zu;lI5e{Qel=<|Y9SC3bEDE-bLXusU0KN*D4;EkdB=Rs<&WoAD;I#_kF6x8a!v{0S& z++gKrnfsJ}d$8&l`;Q^U28AV*trN$?oqo(&M$416D~4iFH0Q>cPY1`Zo78ycu)~LO zLF462uGK#YR^gUmcj~_ctIqm;UTDCjNTt8#r6Mg)gz8^;p)-HIPH*px20YY9FZ5R3 zEib*VKjDqe?th(L@2z4jyT8+0w@|Yzi@(zsw@|Y!_TKvYEnqi$k2G|=<=LZpjF0MX zdvUO|1TL6zRU`WB!MPp2aaI~Pd*L~vX6G_2Yplz%dgvY z4_}3Mi*SYJ>{G8#3RS&3KCugz4xPo#S~!1|crflcG%W4se0`^09;({)d>>a@*zezp z`{%!4#6QQ_yc#p5gtCvYqAhE(A%pafL(%>Xh5DIL^`RwywqDagMO)_W)lYR$y)0e6 z)x*QUyY1AchN<{AFARX6ul~RuKjM-+p8b)tc8C6Am>T3ruYrg7Vt3$PLF{|jnq9|l z9(;M-)E3UO@8EDL`?kz$nw>-Bh{hE|@b@sIN8;Yhu#w*uT8?*hZoyzS@gC1_Wjf)t zuGs&0+cGaJGOVt#-{aL@a^l>v!<_y!p+s|;$!-pwWh?Z#9aW&mk0X@+U`N%i)yw@c zgN{$bwPC7ni?cU-+BLb??qXoU=)8zK)=HW_zzLV-2GK=Q9 z&F0Q=f78F|q~bhcVADBVg@-4gm4gprgCm?@|4oJ-tZYa1MHhNFkNr)b9j>CgY=z!z z$nk8{mOLWl%~7Z=F&_6M)_J`!OzAI%tN4H^&1TMS+w{xfs%QB0jvQR@RCL-Y85+yJ z9A9<>ZN&4x`q&6K{lI>DR)mW3cn@caha=$C(~jxCM5wNoV5c738He9Le$rz)E1M;w zk6zRnz4Tij{i)9I@>lxk-*;9$J;o2k@o!aw+YId`tv1#bCO63nP(+cQWL13!Rb#%2 z4V1SRSD?#rqTG(hMvVLac(1?7JATIz@Axv$_e)mz#A97wmj2YS6x)k zfK8p@Z+#jt)=UUh`mnC5v&Y5jls>nsiqvoKqNZBj@1^hSqQctCJB;|3By%0g-WIvg zilPGjk1lFJz(%=fFiIKIo~1O!7^U1h_@yXgG-)j-QgyxOh+X-C@gsiAFFlSYEtg?f z|EEIdzjPN_+Rnf?^fpndcW;bp ztIu7+$@={3uI$Ihz}fqc2xuCFUg%*S$S3+^kM&X!L*H#SbC$n`@wCRA{J3A|el4fa z5a)x2rLoBiU(>64tB{TzaZv(C#3SX895Q0gkAav?b@kF4U=Wy#2F9;Wi^A#rBj?TD zx@R91HOc2nL5Hi1zB}HhY;@ZlPXA2`Z}EoUD*E`(&K{d(Vt{M|agxM}He#KjGKVU> z+;6;uqQBY;-MRmi)Ph?S!Ollt)9bNWeZIj|1&2!D<&ceVdbH>_)N~v}_BfdyV#-~M z(;N=^oBJufOK&we$e7~V=l{*p}2XI+}?PI=ooq| zzHE{enklB{D^n8%%{WuD$JAgAF<`itEri7YKoz0XKJoDG-W055h#64)YO@pAZWUqn(d}08JfAKX0xeD zfo7Vid0aF`ZH5EtDiDYKoGKmvGPXAC^H-&kvUuzc=LcpS7jv5P-BHapvcGR3|8FA7`B@7+r8lNH z-F$RMZ`Dpe*-5qODF1d2r}T(V!#W9`NZ4VHCSGfLDgA*#D!g^l%dVqt^+%U+VN&{w zzI~AD*6T7{ceNGQht2873(ZqdNWUwmAYT;YH(14o+)wkr0(t7Z{Uv?TU=`lh_``K^ zcF(~FkI%wbemmxk6@yjhG0V}ox6vUu*y^3xAb4HBa7Wpv&J>Bu+Q=+CT#KXP<;x*A z%44?mNLz72(!Ro>5QcKjp&U!`OL|z08q^*aaYn#QDH;D8jK8N_Ju0v-Hnfk5X!q(; z`KVx&b75dozXBsZpx@%9`mR2zt3wAr6*#YZ=Vf9u;JW95fotl~G+1{(2bNG)8{f^# z0lS250i}S6`;ScY*s(A^FsBwdx<4X0R(&hmvcuVTVc_wQ?~FQ*2ON|<>jIMCyQtzr ze8g|IKmGPd82Ou9p@b8OJ4W|N=!%rLfyIal`=|A*U z19~_O(|KNv1}5X*m7`Gn%_ugg`w64Cpnjgq^x^$f*D+OQmHleXYWAb*qma)a68{-_ zLK4h!en8bff?wAc9A)C)mk)+lE!8*lQ==RM%{oJR85s04(n8kZ$rN<$O8I-|zsD>L zJm2pnq@E7^@wa0qu^P6pyeI<21$e^@uY%jq0_S-dgyRD{ufZ-b`_act?JlW@B(=Bu zpAC6^U4ZMm_VEEDylN!&NqkGMp9=Iv{Z((rM^NlJ|KsUB=MMIJK;q{H^t&4vxMnmC z$vyjj{RNsmfp>ie2Z2qSw1PokrznL2FvQfgp@HYjI6r5Ijj(o9q z_mOieYxjJ8u=`~*Pxq~oXVq)sKn{4&o@2*Dyd>%5@qj;&5stESE$HcaAMV~!01tv< zJo;qM>DfE>TnGxED7F`Z`UL}bA3ga(coZZ3-a~G5R)e9n7-q9U_P<@b`{O(V+S^{y1^O!kR6BdDk!hZnUGR8v-JT0Ke~3c5 z+u4$2v#OJOPABh0CHr?DJ@!I(dE`hU{dyPbp3$mn?;eKLyj^<^CO7OkI6L63e3W)@ zcK7=Qznkr4@b6}a=j7{&(JH*#)1p5_$h&aUc zh!}@BN}3_Lygl{Mfhv4h`vBuk#OkI?Mg3*qj~=&ftOqa(6YP#K#C_CpvKILc_NV=F zNNhXo)_c5;_$xhUpz6?Sk3VMTtIz$h46EyV+vtxBR56a#&|MDsdx#8k81inp9CA+^ zS#0wznvd(Y47VIv(8ps5FB&UP0omvX#G~;1wJhRYQ}Id^C#F^mV4q?{MI$<*q;bZ> z%$GwJ8MVp3hb8OrgH(t|-d5d!NoXB&os17O)9ef87<1eTDUeDSSx^EBklK3q0{SI~wbCcpdpp zA3xkpu93$^al;Bz;)MY)SU1VXxpv9r%kMA?C4o&?N8k+P}g9OZKNV=d)+ z6%%1RxtT6$^5mwgH;j2+H1_mqq`y89?;U*nzKZxFM~mmOw*N#n}`21SSqcS1W>ckhn4xjQd+&qwbVt48|e5x7Oa z?nYTe!gHX@MygxXu&qZ&s_hB|orpahxUxpZ{hjfF@0_y5j|ll4le@rmx1uP#BH95E zxHblTk8_Beo9a&m?hJVYCKg1(Uq{3X-+sjdY@glMMIK{&Omg3yhHS@H;s^is>Gp@8 z$Y1NKrmh_4;J~{chY?O)0klnOaV10rx^5|3QrnebQ~mj&t77 zg{*`QXWShSX;S!G4;W<}K-}v?#DT_HT+Y%jnrYz4Ufa#IBPc`UfCE2L2n$HYiP<=n z@4EAxMefVtIZ)JuKM$Vput13IA)_A8oj9c@d+suRcj7OHcN~e45esepVkh=Z?5-;( zy%m1aDc_*tg8Dmm48j12jlm}4rcc8{2Qt;6&Yj2JhsOM;N!b-O7!M1PC2-9vVmZPq z*B}oHY3X%~Yz1=G97E%@_-gzhG&)3w+Y?^T-j6}EJNDSIJm{tRP~=$JPI_kwV#nvX zb_wPqV({x;r< zezIBrK$!(cuHENiiqkfBIi^Ss?(-}AP?BXI9>t9`X9l+V_ze8h$aazXz z1V$NYI2X4zwemO5>jFmJhK|Iwb@4lGp?3b(DE}4zzVYp0Y*FSey&_Hxk2pIABNZOh z#2+EYm;LN)GyC%8dnX$gVK*H+Fh_5U!v)lLQ{+bI_`I?kGqHl3;=Ddt?`%`!^-t}p zx8LBsD9w7)u}AOM=i622kQMj47ihe-=CrPqOEfXV-$1$QGVb@AdE@Wbx7$>E%Ygg! zUu-JW5^}%Z!mg~AvFr3+cGc1Hx^a% z-tw7y*0RZVGx@2j)Yv-Xb-bI7J$T>c%lfZ&)g=@?x!en{j1(`BAu8aJ)`&OYv91P)5`rsW?TvMD%;t+%*xz{zNhnG_v6gmQx|w#dktW`lvp6SrS&lWMI4vWuFe^8Q1=t@m z^IdDdAT`~Znw_1SmTDL~w3`3PFh4(axiu$anKe5jXHj9Ml)YHX(DJn${AO!|wLw~c zEgi9JR;y_fvI|B_`7Q=4IyQXFy|yYxIV#q?r1oOcaxz zmz$fNl(i%SS3?>a;I4F-S|rR$%_^Lbo9~{8w6W;81*vI^3$(G>xdj>5r2ealq#V&- zRgp^x{nh0-vYV48WET}=Cg$g+WfT<5%Fimy7*n)xVMabK7|kGEnvk_1KQ({(tjvrY zSIeen6c**@zzSVGwkSUz9mYa(^QROoSzv6nl)#=^zGOjec2-(KR?cE{q8x{A8L_3Q zi!vsr8#O|ol$Ex4Y;I9b;gA@^ZbDXe#>AY3x%o>BUmCMKJ~byj8#_-jV2l4vx>20e zGh=x{Va5{K7m4{9X;}psj?o2@M>JSAgD+&IW@p`&F*Y|R9r4_pnW_0%sSC1ApO}@p z_+O@o9uD}gGfBg;Gcxl2DRt}&BpKt7Tg5Y`&q~NmTWmI18=ZD*QC5BimE()ku#2*m zW@t(I%l}=Hk#l-Rc1CK!Kj-`BhB##7P(CZX)@x_w<{NF9QM6!5mYd_c^jAAmwo9#z z&0Uh0iiQ{FXXPxy-a*%6vr^5S2c9r?a%!HWwlR`5t!9upw#ZB9#z^Nc^CSsYuk{^p z#_r_EJZPE}6HAEY#7bfnv4&VjJVbO7n}|M#%yNT>R$?@9xQPyJBo*<*L}C&#nK+M_ zLQE%S67z^Fh$X}|#8TpY#Bu}SDGyUoL41-}N!&=>MBGfQB5om86Som-h`Wik#C^m% zLGjctsHi6%A~q1eCpw8Ih>gTE#3rK8VYBN)iB@7XF`k$VbjTSrkBV|)6|s)kNDTVM zEI5{!Oe`T*5^IT0ViWNq(dSz>@LT0D&Xpsnh$ki!Gl`|dO~g846VcjW7MMuPBUTV= zh>b++5!2p&B$gSepjT>{-Z@La~}&mfn^)zphD(xopa&u-Rl{cxIEsCr|)2*Ea%xGV2R zvx*X8IkECb{lIKB!IAirnO;t;BL+E5eG0LL7K|TPqi3iZ5Ay_r-iZChEN3LqP8>&!CngXRiAltH#7tryv4nUZ zv4XhKM2EJCip|6-;uc~xaT~FQxSLo@+()b<))O0uCx~Z=X8G9ui&S|2!|VZnVkj|+ z7)`Vj6Nrh#WMU?W9fmJ-W}6~s#7CSnz_hFDK@5~Tv!`X-`Jqsc>wQH^S%VPK~sk(fzb zL0m&DCvGCv5uHGNU_Jh+-0tzn^Hr(J%h)dIbTr!+KIC%4K|&C@Yd#T5?qw!x zQRKJ@XM|{Sd7529EV++KHM_|j#v@pwi>CqBk&Tc@j+JI3B$H!#+XyM-0pywFt;qAp z1IdfYgUCw^4!;VfqLc=*h9se!9Cu=jP(dz>NfIi_aeu`Ko5*n=$Ou*BcvRa6)#M$> zYlMqmjJQUC1?Gi|N;0sqle9 z{7`NPNC+a2G^rL!-ksb^-h(`f91m(4A(|YIju|1Ayf?Ys*J4fw`cM&1gTCa6H7?z-}+BoAPE6?rRzW3y_g2&6$Bxje8fp@BS@+%=|V#eOq#^rP;$F zZ~gjon&Fg_QC?x_P_}8Q1Unj z6;V{krzRxClH1AS$w!kXlNAvK3<^YKyoGC07;J8_FL@BTAGwv>pFG+@MHm%!@)6|8 z$fJn1|OjiNq#jXO#OI`WND_r@b%>0{N`N^wY`3;Wa zuhx~JubH9Vm4V#p%0S-avX3_HecEuJlZTS~kw=lM7}Gx1WiMQg|9Dph8YH_i#F`m0 zUFqb-uJn;+dZ{a&yuy`kH`6z{(#fk`d>n3iT=T{;W)>}z6H#`mmeSQM15e|zP?Ni89@Fco zC?P*UUQYfRc_n$J$sJl16?mM)2sPxNlGl;{oxFkkGxA3A7s$14W&__Q4c?x;0E1f;&x|+&k`V&kqC0|S)M0?|MPyDQs25B_#;q{=* zo+VT<9d2QS8uB~H>&Ul~2Qj~E$-v3<@l20mx+l2QuQk!Yb@k&DX?Ee=%n;2Ct~G^F zrqeB(*AQH53{gyfmic4JA0&?_$HkRVzm`nJ8#Krye~CPZQ+LCh|SxKHbe8-9jEp{-wG7 znifSx9Svg1Cy~dK*N`WZe@>prE%YVNWcq&cV)Db}rR0vUsHmXgL-I}JZ<1G&?;x)w z|AM@pd?UG&{AKbc@^8s~dKf+8(AHBCYAUn_@+k6m$z#bsA&)0NLY_>1kUW$88}efE zugOadj{bk23M-FG*D6Z|Gq|p}lbP;XCE3LEZ03(;x@*;?n(3KLPv$Q2Bd?Wo+5ZVt z6tjT-$>dSs#ys;aDq?A{joh^;;aY`> zXL>2qYuMnS^kVXQrVl5NW%?>|N4bw#VK5aMhgutX zJTu%wo=iT2yn+=BBF|*{a`I@VcPB4q`XZA%v?v-x(x8+E3&|_U?F1HTX3mgE2e>KF|vvV zAdo#nT4o&W1;kW7Ob8nh>OGJUp-`J@_44FlP8mJC(k6`MP5u^MP5o? zZS+5s6;ymggH7Zgkk_+;VdT|JpGS_Vy|GI39eFL&cak@d|BbwfT)t~(grGiV0gsV4 zu)>byQA~fFJeK?>@=Es5VDfmT-$w3QzqXSno9PbuLu@0|vVd6fOcqc=UdQxdPxhCTW}oQh2}m``5C3a=xtX8H!Qg9`4bQISc5 zXUL1mUnegmf04X`d;s9#CH09T~-WniX2tX>CSYW=48Zc1HfBtQdAhXa;8{6W@ubxJMHz)tm*V-nq6GzM`B}z;m=jXd3UiG!pYgO6aujA17miIu z;WO}58_K21F{2QV+EE8}b3$T%RxY0XTduJ|czg>_^A+Z%<#HA`Zh21XlB_f+7vGFJ{HY+P53AJYw?p zTX%o9=EvCs?zrK#{Di!?F%LDZT#~-+?cVox_C4wsG4T2|&j$Q`#l6#0JHPjwbMdC~ zu}`MVD1STav%Z0qJ!frC>@a@S%-^#rZoTx;2UFIr-2L$!`c|&rO&dwqe4m#RqB!W~7d>mp%0GhJo`ZuUY%m)_Dt`x@p2YMRqzY04se?2?8X@usj}>Bvq(Dj_m5>@p14M(bTRqVK zc0^JjC6G!;4Wt30d1{&+QUa-gXkOru5=ae1^9F~MKx!Zww%ZOVfz&|c3qmCjxjkMY z7h9Okmq0X3%1dNoj=64$zZ}(=gO)%vOchIHx`-)ZiA)QFATrsK)4!a-SZc#qs3yKPsYgsu<@%$(rcg|l_B;IaXYg$gOwV)_1)0$^K zUaL8Bato~)Ik`oPGObH8mgMHkK_MYGFC*VLc&uUpg2yfkGt#x@YSQsMF&=eZY+aUH zl$~zPO~V+0e9h@aIjKuiv$Ex}PHSQQa%<|M)GUnXvgf3;w?fdl4x?A4cV#T>0g)j~ zw)%eJbf9E7jV_SPXNbQM#a7aXLZqB@>}%0I26(2Mnzwe2N zBuMv4L9*+mAn9tk{1D%g0%UL(oJH&cl)PUMS5yBZ8Ybn4?@5{BGP1i|t~3boJ0a){ z%}e|*l`Z}b8MDB}2PGq@(Ms_r+45c}K^pLP91T*S_@3yk5UEfO67fm#LD9=bh&~*x z6tn}=fun&LKpW7p5RvN;Sp@6=L|e4+z*~Tmfs26?fZ4#Iz$L&4pfqwCP_`llDBar@ zD2?a=l!nFwZv{pHrD3ta0^n4j?CLQ+vH!(2$3am991C0uydJm=I2gy8NbtGQ z+yFVeC0NOOo7ADjQX$?fA(31hNkTEXIFtm}5bBx?mNH#DUP1-A9Ci{mk&EL=s3tdu zL>zy$REPsgs3#Xkl;9*6hcv=WbBp{)gUDSYXB0Vn&np{RT z3AN;RnN({azni>~Tt-p}KFQ_=N1EG@L4{i&!>R<=>9?y%H7he1-347N`8`ZeBrhXR zA(z2OLLPa0lWHa8p{@cespw3DYH~THN~k4YV^Vy>&D;VR^&~Wrr>3XNY}mRGbK`8h zzJzmkK~Y{_ZoZtm5nSn6Io6^AjCu~2LM)q4*kYJ1FAOcWrsd}3WTY{-=sBUVW@i-? zS_^Y?t=YLb7_FN1xkZK6+=bTk+$F~O-gxKAY?Rcm315g8U99ODa<$;d<8^|OumnxV zYd5B0e(vIo9BW=yp2^t|yb5DYUC_Ken&z%&o3U}2-x!w#SEc7?EW}20@Hg{0!+0;oC^8){$jDWX+3Oig@^JAY zA;Wl~%a{k5?+aNo^7C!Zi-2PtCn-6u7V`C(UT~ zHG4NR7ki{A2m388v-wpaLbAH(@T3QQ(mMZ7ndb3ALPz!ew~T2hOw1IDfdfYyY_TwHt|9?E>Q+F>66yYFdWO za?>)iFe`OUbJ+msjU6f|Q`gj`4o*?87|;i=IvAutci$9_qK&Ijbc*pdp-}?#MhmQP zD$|3^f<<459kWDS&6uW}yFACi`S_K2JYDNbgN*sQt1u}@=I@5DVAk)}n`{6MV>hjF zSX&FQv8IEQ8*Pyc#{8d$kl`2C_>|jqKw2uiBirRX&8}d*>S%Mbzq+I=_U84%0@(pF z{$p3eG39E)++^cYqo66q+aR%dWL7{lLl!D_IM@K%79qzC~ype}Y_`4CTV3=hZS6G@Ppe9K&f*hqw zQgh6D3*=bIk-lkez`sa0&wtGc;+yb`W?sNo6b+}vYp6>zvc+w1Wmm*O!5Ao(4{uk)a zUmDZ@uJ?wG*s$&K-#h*7vu(E>?$hnA8q;3WejR3{+v~pm_1g*dyKAOJ_xpR$#Jg)Q zt?H9;eaI|3?9l)CBMdVGK0{>$*Hly+d2I! z+~a*4ZG~$?KChbHXsdmqD0KYYjkdsh9Otr=-)yu!yZ`e+C%$X6O`F@gPPI8{Yv}jF zE02#kX}f*e9V4srPuhw;$~`{!xs$dR-_9I(_ZKH^U*5N%bcFXQTkL|OoZDhg*$%Hb znlXOyDcg~6I{)_6hEukd9^e0U?PsTKAzKIfUGhF{yWB4Qb)S)^Z6CcbeCYGHp0@q| z^bauypFeHu>WFEb@Yion+j{r^y^CMFGq!&Bq^9^xIb*9Ex#P`e?>b}a*?Y*}54?BA z_I%%`mcD-OjBVA_r)Ktv`OS8q=bJ;W&;8BTD=GePiGp;G=WRE2k9*zY#`CuK{#btF;tl6*FMmGg zv8SEqZ5KkORzExVg6;a7FPvKHxM2Hi$E5OzeHR?IC#SDH{6vR~wn_VE^*_1jqAjcZ z*F)B=7i}xmip7Ju08-gx0qX!0MnwSx|N{P@Bjw)s!oK3Ko_hwZGb?5F;Tmuv^h zH$MC7#!I%Ib5j4&@%$y5eSFT`rHPkq_2nDx-0}Qn`iS8x(c%Meh&u5BV9@xx9Y!QY zd;p4Q@c}Uq9{^U04~SlT0N5ZtAY6O^SRy_EOc5Ut6dwRKiVpxQ#Rq_z_yC|vd;l0N zJ|K9|0VhDjEAHgZKb2(IHNNNS^qB7>Ex5%f$x-#Rq_P@d4rD13<$Ego_UVOT-6&dEx_- zEAHgZKcj zQhY$T_y90bd;nN-#RoL)+&71IXuoF1^^W`MnLeB2*}DiTiE!$9cPd&W?NX*dv9f@0k@hUawknyCW&CC{pX^Up_bPrTuez=cJ{_ zMSq`ueyeqCT+*~Bdq4m4ytqh5?xur|M`y%EW-cC=8JQV3chH)rkLKIr>JILk`)SWvaW}UrdU8{JQrv=1w>Imh z61P70oi1y)%#8E6qbYf3?|`^ZYSq`>?^%d0JAAoWF!`0m2E$kubd z?|pJ~T>0j}KhFMiV_a6Nzs-66%>{AKIDYx9&xVw^HKT4Edg{RSj<`|Ih* zdR**Z{1(UMj(PaeXJ5^Z(_8fZ%=&Fs-1vyF-&+T!$FnU+F zCw%nVfkTtx63#qXf4T3?aZlaeci&x+3Q$_)nrkXU4~`LHMN+z8qkVhzE$@ z5RVd15Pv0}B%UUoC7vfk5mtHjrcZxG)izC+wj+zB*}|9w<^O59KUocJa20P!2*QQ`^Wuf&tY)5NpH z^TbO;%Rrw0{Rf&(7Dx;xwjs77h7lu(U5R~(1Be5OgNZ|k!-;XkF#~!2PoQEdaT;+3 zaVBvN@n+%zVm2|Ccq_4hxRiJsaV2q;gOU4)4-g+Dt|vZ9e4My}_$+ZV@m1n$#5ag< z5#J$hCpvaAvXA&FaX;~M;+Mn&#BYd4i6@A^5>FCO6VDRQ6EB(Q&@6+@eeX{UBnA`P z5Ze*Mh!MoD#JFG)63-Ja4dU@{;U$qjF_0KcY(s2E3?oJmyAt~n2M`Am z2NQ=7hZExl^Y|Y_MFMduaT;+3aVBvN@n+%zVm2|Ccq_4hxRiJsaixQiRmA&<4-g+D zt|vZ9e4My}_$+ZV@m1n$#5ag<5#J%&w==SnxR3ZLaX;~M;+I5oc7R8mtZ%A@AjkC? zIYn7H__x5q4CASd(M5&$*TTZAw9%8tiD~iUy!*b!{I9BV{sZ0rC3I;2uAo|0Y+Y+s zT*C&`5gV?-Mskhz{|?K!!V+ZI;V@2QhAI{yHzeeu+9kr}VFlqX6rD@3iU;N{BW;@I zF3*6w%X8oqhY{Hbg}cbj3wL=Q++AJ(cbAvI-DNYlySxnUF0X)_;xHqxLg6m2fxF8a z;O_D!xVvlxcb9j;-9@vbi`=AS40=o?!xfnX(k%FMvB}qn1Kdp!wlv`L zf_Z`#NTGHEobm~aHu3?XR}$qh8F|*G3Tai>q{$O3iSYB?NZaj}rr-CKTH;Y-G5<@~ zKl3y5FIw_|@~@O3`iirvFaCpStVH}<*6g)t#T6C}|ET+5mky)kKq?1yg-W-$=)~L= z(2vHZ*rAXjj1|!KEqy+;XpNxw?_F1kK960=73vn3lEmB<+)I=qSYiVz%|tf*J14V7-muEvXP3bMx|4MXo$ zSzT!^TlaQ}y?c-*xPrT#Gz+1Rkv4tCxEXyqzHod(_Msc9`tJ?=@%SsprSP%C=iOL< zXZ7ddQTU}9`bYI@x+53~B68nU0k0pMlprJ;<@J}l-jV6XlU&hw$S~+#McoqP2@U(l zO0y!LX}2UNGCEpIfiAH*Z?RVOsWKk_G;Nlr!yNZ>l$I$rS?P|{!qmv?Lb!GASACUkqETMWXV_s@ zB$@?IGzx6E+R(`Cyh@j7WNy4#H%2OHf=+tUEH5!xbUvTEZ%AUYWDaua<{4X;XjBsF zQX0A>qY^80R%9>>Ofu~3&;{**E`hZQSaem;(KW;_Ms)J0_m6s^Fw<^`=;T#` z8eizlHkgB&RA>~Ruhrl<*%Su808f<}85+@mHc;d-N05is3Qv2_Pa2<`G=J=rnSBgEl;6)!>xBP^2xx5C;9J+C#w*V=#Ut9{NR&*8IB+`P|E&D*tv!!KOSI_h z&~@qIqxCq`Qbm04ui6v_D4+CJ%5K%Pry#Z1tzA%=J2x7#%4|riG^B-x)?$oDo@|s^ zeoFfYLn!vd}91mbT>RK4vDHXE4hmI|JQl!-SONv z#FghN{%`UmI(p*e0f;M8qC5XLnNoUb+6IU#&sF^2Z{D=jW_tv2LLfa?E!E7jwRK=fV^dM_Bg*IJdJySGE; zJ!AHsJ6CJkX=|D++DfN~R#@+;FK$p>x^;+dsdbLILF=sST2N!F2LC$08lSutDc*_Z zzQj8^dRc=Ss-J35z4dJkYM>Xs7Uelc|M4I`V%xMwZ*@q8Ir8uT>-~_bXHhM@sneN3 znos(5hOQR+-J*wAh|Lv_fv7M>yDBei+_{?CUYpQ_O?C!qL+XRH{s%bGb<7;5wJ$8z+NUqm+Q%%_ z+N(k>NbDYHr#;Z*somrB(pJ}dYj@PP(2A>lv|Bd$YV#`mw1m=@n!VUx8<-h@!y{Z% z>%z5lO~KkKXKVCd8!fZ8t(I0DqTRU3(N2r6Xs_8yL$%?>9grbRizpnfMWheYB4T2- z2sOm4u%(yQatwBKjd@&jiSf~5(pzd#XFRpwFZ?yHBtNZWJ1#gN7oXz}bmJ=2PYX>C z)IyU2w9puTEi}JvW9x>XJbd{3kc!EuML$FGHX^5&Me{o2Yw#xMN<@dgm2`Jr<(8*I zgtr!$9-sxHhHk6b+tifv_U7d85GzUP}4H63;sH=)%U)d7doo(JU)AM zLDNpKJa=x6dMz}+LEb6GrWbl^B^NdAXGqjv&HCNB>glKTR2?*HV?;xzy0Dtiy!I*j zli#RL9ZT9O?NvygE7ujSfBuc?GAktn6B~T3bR!Mid51p!TBr0Nty5B<)+wfy)+s-< zv0X#ky4E#8MsMP{)H+zbwbq3JT5I%j>xWtzW3U|))Q(3~c-Pp$O2a{+MdPzzPeWve zB;h3D7Y(k@Iiez_y6nc`vtSD#%V@U>@pW$8H_TfLiwV@i^3jaEHYt)%O56jRmpdzM zJ@NtdPmicEZHzOAxAbA2l0zJWxsLzfZrk3K>#LrqElO#7kqfAgII6npSw~gJY{ULp zyc86mw16>q?49+T8-)1`;zy99kLWu6`wmheK3Yg2B)x?e6639f3<_>gt);Vq&{=_6 z>(^W2m_?gvj;c(DFaFA{ExfF4jIY*qkTG!8xN3dtdZoPwIfq&WgT2l3tSkK#J|XKf zQEA;jF?(0x{~_C9ceHybFwyrK+x?T2c3pzfZiMX$U~r%(4iNA5THv6Td9DHX-Se!)@Gb~=U!DFtq&=Y6jt9j^A=gfF=*f&5SH zIgIqv|BFrcbo377e=6rGl<|^Tj)&~RDL<$wGInhEK}85||3QWImQBcOflG`)8Haq( z%`L9#oOMf;_BAB$6W#Ko>e1S@AxCqSb_YIchu$Clqq?D4@3%&2T_E>-qCfg0K1++U zEM_DqKiEeLjtSO+^D!Z+^Q~!-=iPi@?7vHC+wNA{v;V_RnzB}D=@8cjD}RgTpYN6U zuXgBLrAq63556q?iPES3q(Yi|KM6{8uhPD8Rb(7}KAPWj?`F4JSf;ceAQxz(I{0ZF z3Inwc>8-R5I0bZo&vtkyq#?MiH;#oX``gtqw)-(MK-%KEN3m< z)msZaR@(*Eq}!vPTjb^-l@9u4T3>WNEHp- zd51ReK#UKvi|uHMZgncFk1#o;_02!2XoDpSJKVG|^#)xzMjC4W2pH* zF}p&wvS_Ua`9-TxZ=7;l;FJp-)HX%=D$Q3M$s7x=a?jiSnwFw^}y*9X(aop`PS*g3Nt05K5 zb-7;OgOv;g)kt7tuqM($)?6gGm+K?t>cNlW`c#q@ykV~M;EK+83DpO@FC-CCg_r-z z@$QtMNDbPbC)?0fGcHzYfJLx-6!JI7cMxA(Ms|Y4LZ(4(fk>}f&^}MiOY_!RXg*qY z)`GNry~_zz>SufzYJOf;TCQ$Cp*ra=oKOSwslTWmebe%n<29w6tVNlHM*4jGX#(Cr zLUD4f>Ix6Z2iNN4%T{6k|D$gI|D$f&|ErI>edIMWE5EQPH9HY+B;gG-T!}ecD&y;8 z9W40j(b%iLh^6guS@3&hDPoh5T2MINcsC8Vc8o77nP0Wio>j&-xhCe|otPry-LtWH z$1FpeG=BP&@d<+m^-s^nt*zaj(+ji5rsfqE={tW_`Feb#YUma2R=N4nFsuZLZVKL{ zTbf~h2TQ)Br8`cliGk5x_;}WpcIY3RRC67#h&{G0ZM5q}!u?X!jXBHkA0_yR)5pRR z(~@#0;ElO>y#Iqwea-fqo{G+XR97@Qdob ztqtc?w1=hUjK1Kkn&25*i`xqrt~&jPvA&*(l0!cK*Vg{Kc|)S6$wcj>>!W^k@0+(X zD|eeX77dcyM*V>zu3$%5vK7%s|L>r~3?m%lSa1vr{?Ae0c}aC0ScxS;S)7zUbOrY_ zrRao<_&|)C5FH(v*PGi>Oe`f<5UYuGL?^L{7!+^jk0RQMQiFt|3KN|s;B&<6d6PS| z{P_G=A{bi92#-#E|N3kuU=BjK8Y47=tpD*i8aMtSm~#Q6*HrNsH> zml9oh{#C(aQVX)u#^x2t5pOSElApDRt@t+$nRtz@91@e219O^p@DBx^&s#Knx>Cbu zDz$PfMd34*ngw$wiQ`k2S_j7E&c*!@S+~aX|Jp5B1&&7??*M2MF>9QMcp~r*NFL(y zpB*n@p0NgTnQz>MxyQqZ%N%4O<{b_pG68u5Qi-@sNJd&Qr$XEgbgiZee%A#JgkJCu z$VJ3u;<5$eUx~cHUfu8?B#65&ippYXdn|sAgkEqUBn5FSf;yU4MP+rgXHT>m34)^` z4Xh{hq_2z+$|b_3#7zxp|T^W9LsuD!1LeZ>I8A^ z2P}L2h{I3fKbgyivb^ZNj3~>AKS1t-UQolBS1InOO!Rn;TKUD7Wf30LqZXEUq6&}#V7y3AKE}K`2Hm{6!ALX%C<^N7JHz> zwUj6rjg`X^BnZxfJdC*e>Y=PE9)WCwUhq7m4sonkYr{HXc?WSj@F$3D4DRV*tzBtW z3~u-`t~LuI8t*6)_SSuqLhD56MKl9JmXsft85w1}ZBmM%)t^ z3z0$veY+^l3B5nCGepX?0^fx+K)(&xt1GU{5$_9p3TrOfMG(1y{0Slj$<^HT5Q)nb z<5P^|8@$?Ch|eYq{=FLaZX>a9fw&;P<7>ndfK8B2&_{Mxnhhe2umhJfz5-aqc$EW@ zJtVcjM#crbdYGAgfSC~KQo#!91vfJ;_!~qT-2|-biIod9LNE&}qEU!v1Ir;|Bls@F zA!HjOEqj>>{=jY!X>|;6Wp6kOGM50iL1gO%@d0Kdei8U)Uo=oE1LAAS+8V?K-x_F^ zSq=ONB4s*(F<5k!-3N4N%VY%>8SreEwjCly_;jf@aIn(ugI-n`#$JalMSL7^Kcp7% zFM#JDvH=%??+#JgA?UXOe}stM2@D%*me~my&A8wgBkn++?u#oX`U?rpxg;oLW z!{9533(ki~LsNh+L!`1Q;O)cBEn5Nn7$P=xz*CG{N5EGg+6yQLINE_9Pmo05G>8x4 z_W?hHNTFWJVw4YPK!~_zFY{!WRj(I_d=* z8E*m(TwvNK0#hKND6|rI2_ikDrD1dF^h(G6p9kWTuCzsv z62vos*JWVHL_8Ll43UBaCohD5Af5=^3Xz6Z1J6N>T?71Jk*Ti*=4P7uJfJPh)ZT4?(0L!D+Xc@l4>Y**LUNaUsw*2cC_%Kd?F%gA(F3z=v-|p__4Z z0E6?*@xLu_BSele!Mh5THWD_az#EpLXG%a45K+sprHJFRuUa}pS|?b-xM0L>@Lt$h zfsa6{5yxj^wfzvW{{r~c?Pw_U4ZxxmJdA-;R+^rl2;2aXjjUXW2!!^d;AA0SdDK9Gw$hGs*9fEOTb zUv}VdLge?==E#MQ;%bA};J8Mi_%N4O6pUGG>IIiW(qG2D1ilD~MtmR8 zUJ9o}yaG7r9#o8Y46wt!IAjs;1YGXGPbtU>;8}=N&;%S?X0|#3cnNX{HrjpAiC}94 z7eb`lGl5m>a8kj2jcVXAh}fI}hU4yv#I3;lA)&B&68IrR8tT}G$OVWLRQ`a{ydO08 zSu}7VL_EJ782gZEBe)4-M?r!C>&>2UznLO8Sw4c)z(#N%=kHhn!{~kDW19r))I9!3BKq3*Z z1O5b&4RZn)JZ+Yl4(wA2e}PTkN;uR_AYzmP{0$<9N)s^t8JwYDB-jXfSSolH6I4hc z;@WfYaERnB26}FU4?!>Z2&4w_3gG#_qPMExXTYbQM?(>>1U|P3gO>wjBO=>h071M4 zIOruDc8JFS2XDsKqo5ez`>)^-g1#2m^HsCrDBw#F>8;JcR#iCOVG{&=0V4ji1$Y`F z^T9K~ORu4!u+d(}@t=(!*~fxAA(CM?aNiqro1Z=g()Q1A2A)*(25K<}jz|X1w0@%p7+{g=g-?R?}7C<(k zt~y}&2RLLAPjMjf8l+wlfO;*q4)IFhBm25(OBZzy) zMqE&C7mHp{ZVO9XP;T)`Tu|=hN*wrqio5#QHqJ8c+!;7Z)-xmP+$u0@y`ifz30F5E zuMA{wsr24vGYbYYV;|l?nKf07LHi>@BbN|BiC!uNgy#IgA9uEuoX_VtlPcAMNjU45 zX}8soZg{0@y|NFt%N93TsoQN0&vO^w`UxBDMC9l0y?dU!_j!NM?|q&(ca9Q(_mK7h z?jK!g;~w8}q7m-#ts=H@KV!F3Ukr7;^YryhCG}<(vo_W2VtCwmc2uutmO8F09Vr)% z@HgR;5cpEh4a_97&N|g+|FkuI{7tFU+%V z-3Dg|-|Zv(rZtU@lz$ELwJ*!3Ptr1(J?0B-H}nb~ z*meqG`dADs2@a$Q=20+Lf_?m!W@z}e=JHK0>nhZ?;ACqv{cB&C-}<~v>!A`pK&B7G z=}&)5f0m$6Y_WmuyNmC?buC_Iq4PRiR=;Ok*V;ZlaCp8i#1Ebb4IjfhZ>Fz>=xk`@ zq(3zBo@b=#TY@XyYnSd)`2Mc$r91ilPH!K7a4*QqAkTwZad#uU^Pp6^ym+D$?%Th+ zk6+lc#4F6>z1wb;9^cmWH7itKIB~CZ>$-dClk2!Xey|C07W&_`<_sg#-SX+zt>EG2 z5cpWzO!sZ3$G{zr0{-|yBa40yQWr??dJYe991Dk_b?}aL=oH8i^y3cjn^(HK zEuTQse=f|n2zyM1+uSoItdpfTdg=4`jy<)GTLCsAoddH|q2&tyt9|f_0dO6BorZ8^pw+j=n=S7GhFIvG9t>B5B0vXvAd?fTp=;6>qp$9`h3_Y;Z4gnc^Q1E{5 z`}enrLx$&ruv7@spZLObHY{xn(?`V+JwoU+b-4HNKQSC(=~0eQIUq|4@yaylm!+U5 zOn>GJOPdg+S(%cUED;i>Pl$y65w8qOPjLK(?Scwze#5iE4D5kczZA-L<2ORpZv5Wj zC8+)&H0?84!38eC8B_4sjqQTZZYa+RerQ>w14p9ZNRSurj)!b&1D5x zj{^?<2^o&YRa927W#1ZG_SKi>7CZec@%^_+*4&}{ad!kMHnQZwS+E3mA6&$rKjrKyjQvw#d6$uXagE8Gna9W@ZobQx?y$5H}0_^+u01@FD#l4X(E`?yu1%}_m zIEH8iZw+%|OFcBww0fLJ19t!p{dkWu9(D#`tGENmVzdiEg2Ue6B$(o^Gl0g=VIN=x zvn<3fl=0|x9KZsAFnE$KgsB_&bl*lUysdNN$iF-Y-7eg`h?~D7RIm0$V650WLB_&D zA`F`(eNgbwCxtFZU|zaK=ze^gdu8e>$9&`q&xNHj%-F-w>83SD8ECd32!s3jHpB5> z81!Hl(A)z_vTF=(0U5I!Phziw*y|wnI*7dvo*)!^g-ueXH5mqa`q=Or7U^jjz1)Y0 zL3h9texXx=VPHfK0PNt&x6?W;KKR%0eEkrcl&T-VMgegFyP29gs*droU#~J0kp2;hy>pU zi?9s<3L0VdEZ_k)faXCMJl(y*?%wNMpa2Vm5$Oh?p)WP?wZ9q}yJHmsx;rejB4b-t zaWL^C(s6610^67O^S^rfgXLw+oa2x+cyT2iiS2YGw$qW=PDf%p9f|F9B(~F$26Gm&lxkkAT~w_X zo&y>j2Wdc%kAgUr8%pE(MH{O)gxgsRSo!4>R&lzQzC>p2Y(bdpUD z*)QVSRh0LusP3>bx%%>c71bRwofXB)6*8y<6s6b+v!vI~l1^`tP&R*+vz@^Io<=U?Uu)JS@YU=`28#byd3kBt( zmBRT8g^Sk+_NoA&v?~6>@%GBVSq}heC;ro#0Q9hOIDcK>RzBIf;Gt`~E`TQ|kp4c# zx`6P-f3!trUm?Rg;VFP3_q;NRxq(ebsT`Roem7opOXdLUq z;sC_xLmL59zS9<&J-*_A+;bcqkfr0GJM0L1*m2;n?EvcDbA)}*ao|1M0n~lq2>ZcD z4t!ucfXaDC*m(zmc^iRw8A9NQ69T!%3V|%4?zAIL2;?3s1hRy>Wk=X$%K-&hyljU6 zl?#qIA&`5l5XcgSpymi$a}cQ62%xU%2-|cJXxa#%uH^_kOo3UTSkt6sBY?_=BW%M# zpkX6`xp$f>QA9!kXnU72lT=qj~=(KF>tB~#5brc!UNX9T6JSM;i0)9ZReZ|W`GmE&@roHyso zi8+5RkPGHWE}Dzw;<-dFnH$IrfaWpIYa z@ESftH2g-u2pYtQ8ZjeoB#fjnUXw_C+f&;G<}aTE58z#SN9q^1FpmYe zj5i}@0#*zY5Wi7~pq?o~{A!s-rj_Af@FENxhn;{Sk7g&V0jIhICINp_4&SVRA?^6h zR~fP6fp{TV7%Gex)WS@mT&Nc6g=WDu?V0vX`=^7`(dqbfa(ZZbd|I8JnJ!OPr|Z+r zX;;xx^cDTZU@=;Z7n8-I;&@Rl&J@eVYO!8y7F|BZb)PHs*{?F+UW5O=F$(UNE{JIA z&Rc-JQF!~68oq`3(Pl0KCUJOs20M@HReh?cx{~m=99{-sOfSVQb}4$P8*gS_N^M=w zbajx_@OtJ4-7{0Asq$21sybDhs!uhhnp3SQm(J-P-K(dLt!Knff#;uq2ADVnCw=5NQCY zGzw&z06OVFsFDJlssO8Mz^eu@s|DQRfL&hTmk10C0LKWhECxJF0MiD5Yooxn3E-O! zj4J`>D!{rL@U8*OYZZYnL-4)|b}p4u+g$Ri0X3)+HLAwcxSCLt>VP_=j;hMII-#nn zuFj|>wX9aus#;U)YC~Cqz-hNCm~*C@3l_4k?b|ObCTq9SkjSOHq`| zMzO4D)~rOEKs0g6se!U?*tn7El6DQVI^XwN`#FgB-p~DhzQgPL&+oTiZl3ji*0ZK( zP0xDv-p9f%frTIWl@+>u&S{K|r_*Kd~e+w~Vgzg+h9`uimP zcKt(=ez$&ujBi-K1@r;6VO>4w_sfj+_e%Qp`uin4Pc&?uiNBF}%F>0|D09d@R9U>~r*V@l40J-T(SKtK_Ko-3Ux!RmuOLdxx`-!S_KM2Y00 zWN(j%Nu4MpCU?>Ny!ndq*z4dSrSb;o=<`u}s5V!kqEyG^m`P>r zP)ntw5Ga324Qbye5TSIi+Jkm1|5*(mgytytr#Qu*YgeM8B*x?}Ua@+iBAcb4d5Rz6 zBg#j59VpN8ihju3QodVarTK>je$Gj|8S@}J8$EiQOxM%O(H!$_X z*UOt-ebk~C_H-+p%Q~&uswmoqgVm^Z(%jnP;@T7VW_K@ES>C5=4F0aH>W051RZH>r zQq^MieEH0M)A0ATefQw+;Qhn!yNRij^z!iP81`fN#Oept(#_@PtNXKxJ?(2c1+cAqB96Tpz&_n``r|+^^?}^- zuj+4NXZLjf>>Z{)oU`Zi&u4qvH=`0I$&r~_zoS~IW$ETUW50UE=9&{3JZ<_6t>{N* zDogT z%%Fy#%xKV<^lk{(o9s;E!JoyLkh!Oox)RGvf4*f(O3}~Ew#hBpp^J9tXrH#pofn;| zAJ$5PVp4=&%Yj_ge9>8bbq+t}$8yyh=kR2Iwn%+r3V+d`8R~^u{NVt$qP)x})O+3=Zg=@^ zpKe}$J6QQipWB>UJ`}Y*tCglkI*q@d6ktoF)Ir>F^~48x$0V z+~Urllqlr0&aYdSE+YF5shB|}8IkDa(}?SYxR?EUPZ@r-wTx&Z@DH;L*~us)bp*=V zaIgXS&K4^SW*f$f<-}7|WOAhal5KTBYH8>h6tTp%+HrIZ+Y{w~7jr$9fTTqSqs@h> zs#$R=W>79viBrYI-ET+6`X3%#cGz6ku*I?tZC>Z%f-iAwH&Q)lw(6IZY3DCsrnh@T-4%cyKe$kkkrzscXhWr zN#D5f4J<+_UI*Q-hE%;aNk5&UA2lAT5WQM%YVw$Ise`D<8fVh`VjI%*<>=B0@mk!3 zU@b0Ai(Bre=~xQl#@Lr=wpBH$`W}%`gzJ~sR^Sfb2rRPrKrjzQHM_%Q^oNM9yENLi zIw*FDtvt!$bcHJu_3p6~O9Nxm^b8-rv{G-M6m;cp=QXd3nwODMGAJePQc6j-UrOAC zl%l`0{4!0~8)V*RjSiiqzKkP}x!tz6ys&B%HF)h8D^ZgB;e*OYOlcg8sc@~CW!tZ7 z<}Y>^w7%tYrZl~1Dk4=*_!nVWGzKDNTjp5o$Bn-s?`zqOzCOEWFg86}6XWT>p|xKB zJ++k&b@cz=P*vkgSX$e*p`E{?G}+s78oflFQzN6rdU5;)fTDx3N%NBCCe6W$I=i+k zJx@{Y!-$#U!kT+KZXLH^RDkA-2+%eo6eBYeBQxaDe;Ju#po@{2q8oB>9^F)(*AaCw zbv_98RihI+*Rac_L&uuf+C;S6^-Au{h>SO0dGfmc8`)J{aQliVGhm z6_*KxT~oz$QpIEZKd7QPRd->cLKn7;o6!0qgV{E&6oD25rb&IQ__z9iI{G|uojNY` z5bc-{FJ>*&A!aL-qs1l2p@>;4XRBxGw$9ofn6{dJSj=3ZlGfRaSvyM3+C$~BjzO+b zN}Ar?C#^Kl=U-;3p?UqDQZhUx?ke&TlT{|gj7=*I@|n0WHP$ahS7C2yMMo^!quOs* zQU<9haW!H-+cqtAi$=80>Aro;&KSJa(;3mTL}$3r8z21Fy#XCHWw#Edn=zQ0X12l~ zFm;>8oAcHXZ^Cr6kc0w;gvdQfTw$Vua6$OiaSri#7hI_Oy z>zqc9wl$q}%($nWSbX+Wi}mdtu`s8`-QH6yIREpd=IsU~YF(h^$oCDdbxpCEtqpkC z(^@5yM*d-`YccAbV${PVL*+CbH5EozqS=HLcVx}+XNhz5XvMNGk6d zyxVmVBTKA+FP3?fP?7QfPznEL9CX0^Yoml*?8t4D@P9V+|3wMqTG*S(qp)TO9sG8` zM+ZMm`CrvR`Jk?yTtz?rUzz=r%dgYG*Ki`V(ZGK_3?l#4Jo`7Zf1I<{^*US?qQy6s zdRiPi`G2*=nElc!HEq&ptY&F?3)V8@;|H&+{?;y{EbLA1weC&jxAqL{s_8FXw=}i( zO?g?*=UpF%nKk?prmHaUO08!n$r`5V=K6$XC|X!6!d5XCBXj>1OVWlPi?QgnS%|y+ z>q5NYppcPk@e`4SQd};_1#&rdEsD%Z#p0YT7Ue9lC}-OG;EZaF#5`#;I^B+Iees{Z{o`}vyjoT|5WOpRENnz03Y&h7%AD9?`?pk8Py-x*ai$b+1wt`id_;6*p6@=P^Amm0!&7gCN{*rhnhw=zC6*h} zVy#q!i>m#Ak3s;|?kU(MmWP)JlpN_w1lWeC!WbbE>z~!(^InwR)IH_`-J7ToGn$(ZP6e06=@V&B4N5wGYeY z_@P3vdYx>~a+G4^ic-OhMkS|+`lCJ3)SjS&D~lLqU{vJ) zJXj35=-OSZ={K`?qK#viWMZHhKA3$?U5!tx+-^+!Ag5$|53X+VHQw&YpYO_g4P1>P zu$BpCN8@k3B=9v>g4^`tE+(@^yQ7Uy5oJvG=YMo%{d-5s0`fZ-U1j+lTXJo&r5xD!0PD3eTrMWEH9tq>MgPpUX%})Uy25Pty@r4>)U0asrgQm`sP2uT1cs`jmZJKj z1^%U{Y|a{}4qK38NhVM2#)i7S5@Q_xdZ+jkZL?D-_M)wW^(^8p+U%*3@JU-fl%Rw4 z6VMMV75K}f#uI1P?nCj4@hAR>`G$qMrYa3Cvn9hVN5;9``D?X>mOl`{Ua?P-K>LQ_ z;;B^rysE9;S^m^dp^UgQ&~>|w=kk5E`y59xd7w!65KS!>j(8s&W%Flw-W$*4x5u6_ z1g!&k6J0B7A>54^bGvWD*ei-UvY5w)vL5Oi_w%Wsf$u;}D@|*5J09A~3qx73TDX-z z7RpAc0h)R`?NCj!? zh#d%PdY+Hlv4!*J!dTC)z0GLnKSif={&g6OZQmIV1hJgOVe#{s#+~78nfh!7-xAJl z>^uza*rcL5mRw@#hhUR$vTli3$iE0@-Bim$ekGg@4E|^Vyu$mx4_dS8u%&sbnb%>< zg{eHz$zo&P0jH?W@37@11fWf&#PR|{NtbJ#d7X;toLIL2MK_gL%BJ$CoGi>Q2s@nZ zk?LAr-HR;<3=j<#W7(MFlomsIQZz2a7E} zUb^dQHH_b%%zih$*Ty+a1Y?Q#v(~%K%wK^fVj1u?UIMpu=2My?s2Q1~X|g>uH$%Z4 zPD_L-xbaAS2jdRpWGq20m~{hDPTNIfHsT2LJNvO)J3c%YdbbrVK*O6VZ2O}&&gK8; z$L^apw+0?}-1p(0fqN0|Jlq>`XW-s~I~#We?lRn2xN~q9;!ek1i91Dj->e^ubi2ps z8#nw|t?<+R*_|%2wMi@FAF?m6l8JFjXoa*!7h&yK7W@cvk=*5nK-8(PRE}zd8jrbkbtUF&=GEa0u zQ{9dU_ltamk*l{D_wcUbM5GrbM=M5CLCA@zaAHHTe!P?nG9s-ScWKm@O7}(8M_G4Xn&_FiE{}wa=xkdcOvj(yo z)IVqQq;%GazdVoys6KOe)j$^6qX9)Vg+f!WA>clyl?FbJyUy*Hw*@+|*39OA4rGHu zRwcOIY5MsT;W@o9LErLMqEp3b&@p!c*J9a-o1y`Q&f9AVU)eUk43#uKjX!Dn8<&ew zX=&djRl#Efy?&z$JqRu3PjWj}>bxeFb#f`&pvGGGQ=z;*$?(3GI{xI+>@{97xt(AS z$c)^Max;r2HSSz$>Cn;}vC3j7ScUWNzKxefWtzh9K*j?^hxkidaJ)ze(P>)IA@7ug zA8ngrpjkAe$K>&-<~h-Z@tDX`xR(^J&KsPnTLzEk4Y#qdfuh|_1CYQU@=a9;C6^PGmb(p<3nvmvZ&*u~$`?Wc@x^1))A29p(s!;VQ+LQlrWJbnnf!TBU)gr7ALf;BR1 z3X;^_{DC1XUtKee`wV4?88;6TYuJ_zhmT;;dL40}w;xrMfw(*14#%B|I}3LX?n2zb zxOd^M#+``!6z*-f8*nSf6lLg9W$$A{*<_~HB=et!vD?+4se2dSz;-g8Hkow~o(>0@ zlHcBDw>XlSa>?dO@@tx8lm_z+lUYQ2D;6Y8w`rv_?8eY;eD`G5FG%bOLU&fJ=zNQ& zr?eQ$81FuuE$#RzR=mRs)+MD0zWO@D%f|U|)~myI$?q(bk_TT+Ts1#`2kXq8BVa>Z zxrfgm!A7fZ-ou|A!TPJd-T2uNEKdEp%U-{cES_}<-hg#&y}ik3P8eH%&_`Npp z8Kc9^k3rF&=MzQYdn-lq;qgdCaqYIIj>8fc8guRHB0rP1RmhN=e%qZ3i$L#!0 z7{vvqc}@)O9bm(`K)=2pAhf-fh7gy;_NlX{(-`pe2g2~aaSTthO2k+ zy@~8;^^RaZJBc}6-`y#iQm3DFJHAE`OMW{=5Vzx*yV}fht!PnXJf=@_WIP^B;Y}1w zzPKYW&mn{<6fVYIJn`L*OmOAQ68WsZTa+N8(VdtCaU#+j@LGwN_03fNXA%s-&8gfu zniZ(A(fqN|>}xf(H@|xfs|@_!Axgp;Y*YsE!O84~kpt29rSm$M1RECARlnLe44O9H zj6k-fp`*nLSLF>3-bfHN+`Uc&hX#mlC<*N}kw2fz((OBt@@+AO;*KDnvz@r_ST^W} zEbMF8xx^NDq-m*EIt@qYyD-^~8C%igdNW!IA6#0zaR){M*do?g-ifas%X&Kh!j6WD ziUcK&D*(ojHd4`@`0Ha?RL3hROv&?(t8UVaDLqi_&?t__u93m#z{hs^4hZa=cgflK zW=9@%Gh43S*@-`NGaEEMMdsKdbQ_h1H(12tj~M_XBJK#bC@rOAR7%ldKjSAnl1}yd zN7GB9?#Z&5#%JI)d1?A3k!*?JT^r9cRqDI3s*lJ%JasvMgE0%2sff-{!o5? zJR9e~3lC=iI}GK6Ca|ge;R$SzI_58acmj)57Z2e-fle>AJTgRTx!27MW+OQtqEW?< z$D&$zJ}9btUWDPYbbCxuAt{<=+<{$#m>vty(GRV`;d< z%(f8Oim}pIB(kOh!8lAu(yT0OFEZA2Jo_`Z=Ph{{x{9$B}xm5(Azb;!s2jkd~*H^mL z+zvl@oFL&Vorfp-n1`nQScejmN;TE^61hoh!dU+gbm8&ijccGuzWZ$!!7oi_N7SlV z{@xVUHR_em-0rwD;*6S;R0We!F`j8KIcYeFokGowhZ^`FQ&_i&TZ+W$`x-f>_)Uy~XYLYPFC|jnv$Z;|K~j!X|fqV9`}~o-ZbE zRlS&Qr43?K;#~#yA^&nJ3sYw%@js_xMqKsbJu_H8b>wY4J%fdG48V~%SwEJfAH{1S zsd0|a6ZxGPY@T{#75_4W^$dS_74p&R_IEKIlF={%OTaoFR}C{O{B9mTjZKVrO`c_{ z^ZjAkjEjNA=?y1cWJ$cSRYa7A4vgUsOk=$gZfzsy9^jFa>xb<8ac$zydE%Wio+r*= z!QHoDbYQ{2+j>~AHo&G*n%xSPjXLmoe+{c?swrWE_H}>bITiAV-|PqL&cW{*#X5Nh z3fV7aun={08}30krg>y0>**LICS6^gj}Zu#NZcTz=47%NVGQrZY9(VEN+ye?R{_B zImYg5Ak)}+4P+Vo8pt*_Ujv$P*ENuC)N8mJ*03=Kn1{|{>8`1R zMI{~(XGE;-!*9Z>-UYq5t*@ztc13IL3cP9kF`>1R?NSVf4`~0Gv1Oo0+G-1VP6gHs zq!ngwUn4}Ccj63{7mBkl_&8vuN#-$QB~FW)3;C=RLzNbx-$0iFMWym zf?Cu;4%?yY7l<`!n*OP=SEkJGs9PU_C`6uBFNxY8GlI<8TV(CeiBl%I zFMAu)Wlh_v{ZzIn@F8Sls(q+2y(=%9gQMWfh{3D8*KN?cbvh)a?ib5Cjq%YR_^H_*yinqiyD5e4Oh{%8!A!j zO_nZL8uR^(odfybHn1+?y%YXbRCHu5(@^FYOh<7-O%YQZFyhV-fM!E*kUZv z2;ClVQL_!G!=Ju2(ip;4dV_Rbc{16I*18=Vm&gsKi}AQ9NUwK04lG88)){9pYDBfo z(<=>hY{{jL4mU{uO<*-Dh>6(2ZHXApv(mBpABD9pyf&!Ut;pq?A0e~>s*&!U=ONP8 zy)y}NaPP$PnsnCHe*3iyx`_<a-wRXQB)aQ0| zg}hjXPB&SNsLMQQE}IzmG4^otH1X1}{PDSLpgM9GKR%beuJ$!};XF1$T{?uHmepa?qT@_g*Z1F!Ns=Ck1ezsiIAG2_SI`TqGVJop%J zQ}I}FsKARw(xZeKkpBz+Wj^cV%=$$dA9Ag9ig#VbTLl|_EEFb$Zn+T7BNwoEH8qaU zUBDKFEx>Ep$O#!mi&GpPdLc_OQ1H0w?kwK0fJFzTW}#PMc5jKy5t+blnDs92z7Tdm z<2-)XLN-_(I)Lw9h;zfFEBvd4tc!Z{VBWHj<=s$q0xE&4%5MDp_ts%qi3$`DywLHW)Od75nI|NxHa*_Yl(aQ%zG|o5w`6;FkFT+vDf$;Q-0$ai&4DN z!tX(3N<9p$qNo?dBio{@f8}>PYlcREx}QAqmwUK!sdle=!UYzE9;wb#C9(HKzJOer+B*^ z6?6FCmN1v<)tk?|6-SMXaQ@J(7$e=n`LSDZy!Nf)tFzfs?;I>Q{EKYHV}7~dQB2WE zOrm3k^AgrCdC1Aa48p^~TWS+GUdApPe$nmbJC?Gjz_3tMK>C(Hy2#HgWxdr1C%?Ls z-5gm29X7&?gY8AEEOy}>4kp*vMbuQc>k0R!vV0imN( z>r26cY3VMQB~}ZFaq1^HD{=ZmI90EHoe5u{+Zc?$A6VSj&CO?1=94+&(;rcw?)U&XBWg;}tQk&^J!us$MyR zcUXb3`NtvNcLlpQwEs#B1RUEf-9*5SK!6CqdbC_w!B4DU(dxWD{I?Y>)Mh_~E;*D| znr4TmwlXcaC7MqOYgbCj2&Ffa71MxuVmsKpQ)7hzzS!iG}O4alehJh0=U$mO_?*Awvz{Pm~ zEk*yU$ty*_EG!Qd+B5+SFVjE#!&JU^HJjCc>bGKKNoPiNQNoKuu&n)*gtv7W22;}d{zh3Q(hMNUwX=&*}}fSF~#F4 z|7x?!4hv!ykK(Mc*-9zvmj4-30@KqW6?JjQN%%0;`Sr`!U0=_&ui_FsC+W22;} zJSZ9s+1DLI502tsgt6^8cup>S6pu{i59YFNLD3j!9=~%C!cw9-7dBL?sD#)zu?-rN zaI%!!uJol}!RXotYfohR9l}WTJ&3UsGv}Xt={{|8*^gX2ri{#|M&x5L^LfS0=T(tU z59GsVtYNn4@1!~&W8ngM8f(6=Cgbbl9#%&-WGO05>ToDrL#e$9iPi@byfJz|pZ zpx-z_BorR>8xb%)=UR8XA}VV!W<>Bw`OMLyGEl5xBaUFJY5QyhZ*-ik!`fC8!8hfz{+Zu6#o~0m zN56NPP+_Y_KTGUZ3GnDkX9hjIgX;)y1qs1T)mRo%BjiI}vBtstj=Cv=``^y`sH0Q) zklWcX+jKZ95=ML*1))hJzKr5)Z)cJAaHPfzf^~BO!{LP<{FU3;YBjzG54(d+2~JKG zEytl!!}}Fi*zN7Ggt{HWQhD(m@c4cb$*b>R$?c-Qg8_XG2E-mGw-vD9{xiX7eSzUx z&kOr)Lr=25$X;Gk&u?AF29I8i-onmMI%2K};5Cd9i$%Z}fn?EZ-Pd@fO&I9L%%j|~o(&vQ_60_Gq8;yR6o?l$j6&eUiS{j! zDZ1*HKNx$@XJTKdY4A?*8jH@ep2^?^>tTEN`tZlsv;M=t8wKV za!t4E$5P;=(Jdd26ED}DYHBYTsL#9O_@5$=x6X0rovf$p77Mh0REu*Q56AHbopAQ3 zw&{#`p+NZEN~~{!U5j)>AqR_JitcDDn(q}?U7LdaSU-Susu#*L%?-cn`U{`#Y3Q>~ zShLXQQ?YZw%Z$O!58TP-d%pt3@ZNW^=nl7G!54$#bQpBI&~hM*XWhkis`jtA&)sa7 z?Gp&IWN1=Ufc<4O{=MR)efszp`r8#uc*zJ*ABqUdxl9@u%f)iC! zzNR+`}?(gWKWe}RKk+{8FP)x_dCMG~0exnR-N;QZ4NFF>?Wgf7P-u^eH<%5#r21KXc8Bppv9^`Q3#qO3=EQ{{bAY z_V(lhAAp(W9?4ffz-Fr#aK3whMXAsK!7n|4wu~IfW6N+<3i>-=R>o$iZ~x3|%h*hH z+fW|%AmngN>vumMKg@p+%k;&c_?8D*%&7f0VYIfO=~-Iogys#yzx)#BvBl{52?id_ zmdkk^w9<*!`0cUXg8hewcXlQH~MVhOd0Y`)*_rgT6Q`)5Ee+ z-iMA9t=~zb&g8*rmvEm6#nH)l=4~?5XesB9XG+HoRG#xZDNkFV$57I^2E5J@g!wKAnTXLb2qUKUbkFP z_~lJ3EpUT40^-q+HN&m&N%yjDaW^9wTqveXQg`_JV>0v-mDlT~ab&C&`N|{8ZwH0% zN3Z3(!|=R!&%NwMudA08-h40X;o5Y>wo$ao^Fj{1tikYbR{kX)P+Y;d#JlEBaGo+b zKbV|oa2_@}ADbK;o2;8nPOZs_2dB{F>^3=x;M{Ih9aaf|WejS!0!=3gIXGQ%-KDnA{u6_@Vn*cn96`6zoc|)zZbS_p!O^jyS&Z zKDH({=oe94`8~WH6F5!3lBVPP#zwJthG3h{a~LVLtt)8Q0d6m5ZwZG>T`|@y|H0f+ zf;H{PAU?K)O;z&-@yAN=fG1-R-(P|g-mpQuzJx80I1(%OfbX<~KXbdK^!qs_;iud2 zO5dk2Bw<9j9WTW4#hcl4>f|llsP2plH`x@OoK)3_8z=qog7$3gdW=FdAguz&FMeb!^iPhz9m|obx zunAaQOzdmN@Bm9}ZS(u{ndMl#`!3^!KBFveoTA%6G6SjV3|$6pY5(m{Ui zVWxEo70+#p4r2=cmH)HI`PW)L>=8D2SmE1fy+2xyXNnp7v5MC=&5d)HPVzNkuO!UiKUZ}aMw1~$VZAs>_Ps?Bg{GK zYfMu7u!S(qYFd1>n)CQQia=p%^}s{Qy?xk}o%kRG)QoDHxamm2 z-~{U%(BzuF+QQQ~{8av_@HoyQ9BW8iZxuJPs`xU_Mta3U<|WQTL(8Itse?^1%=iZ$ z{!3T!O}(KyFT=8rf5%yDkF(%YX)91#W`bik*5@_p_^KDDwP*iO_^@qEvo32DGe+&@ z`Zm@(^l#tMgc;kSErgHjGuVk^_4BA>AX1&&hMhjYH~+^r7VY&mwovDz*vbcd&(}W6 zBGk{m<4-;+EaUHZ^`m$n=!GcG9)p^O_u_pXV`J5eQ9S1{*4rxyd){M@vA9kXB1Nsm z0}?&0MR-C(?%@rOvHp&i{iMMoUT?n>I)`nzADdW@$8q>6-p5Bi4qNHFNM8Cl>untZ z-+hAokaL89r$joS)&$rEg#HC8-4lR1BQo^t;6H<|P1xW6Oezsa;%WUBZ0 zHFQtzl#TLXA^E%y4xIG8$iweZmhuQ!+u;`2$~R@38&qf0=$kQl#J1j-&`2` z4~1{t&Tg~@w@xE^4@v|1t=FVg3AZJ8j)#2~U%_Ic7m(aKDJLI~ zOfuyf`>4Y4bTYMcK-#YgzrTWwQ2o96i3+BvhrM{09dO({=f&f9u-Ht!I^U$YRztD5?yeL`J_? z`Szz--#Dxj@*Txkyiw&;_F*_F#@V;9lDv&=L_ut1LTJy+*p*jl3$J4AghTy>E*3IX z1rx`IE5==Dhj{ze+ntO@O1h=-A2OoFJV$tmQKwr!GMQJ5b8m`?XgMfwQDlpPRp?%` z)F22EJnlf{Q{XfV#9XR%1cG%I|=P8Juqgg%FgHjeu6mgiZh ztDCPJ{O4_Z#o0lYEDaIzjDKdHO!gsPas}M~q8vj_li`%tlY(jtYbDFO(dYtm9kUzn zQiq~D#dgs3b1eOJ#?P{VwHAmsVIQ3!-%$)Op5G%{v(PUZ$~k8A_2*AK!=e|)UMt5! z<@A$<1fmdM<2?Gl>4NbI&N^ix*&yt$;>VVb87ILKGk=b0;mm7eL}2U8Tw-(OMLLT{ z^uyR3_#zAIJShjCa@eAcCAN$Kon(06fOa{2;fpN7bp!B4+nlKPP5#hvx8ViFjrFj* zARYB6P$~}iJuTsgPwi=q21z-6KE+FZWLdYwHZW?aNO8|s7@b;;(SL~zPgP`IP1f}y zO{w+Q4YG)%7n5u=18Y!`)3|F8@%C+sOMIRZS_?r?t1jux&oA0$9>skCat#-4nW5#9 zpJ|O|bFW}J}!0{9s68E|&B$Zw`qH|fu4U?WPmd)HvcoW52T7IXlTQR<_s z`KFiHz+S~tbdIG=(#%sR8rjc9w)UtkvIzTtojLsTmsrH;bhF3-*=BW4qo}WOpTRA{ z7m&vBBRsyS&UYyKd*GqRfsrSE&*fZbdJZ4?G8^GKEoJ67j!0_1fH=nhA*b2yMg`V< zJYO9x7{sB};@p)Y@6@TgiQ2VSQc8!8r8$_m>V`IX7US2wxdEpf{*(V-l8? zL#O}#6F7%#_kM!`0vX3_A#-(3)HkN=(B-JUZR7oBtTjz?&xKAC^!%Dj?9lm-jvPFH zCppFK~eOijm1US8~?%>zw_Z>$D*5fP8 z#NIN^k?@zUjgyCNr*U$qDf8olUmw|LIkkdMe3f-hte1)ASQ-Rv$~<-G>fEEKK~#e* z!aktIEb5m-mokr_kkbdhZhRqXk1V0_g#kxb@|~};h`t|4sX4WW&Sf?nIyckWOXPNL zW>k!z-^{c~{LReJ_A7Yvt1PtVC|TMZ#|?s>UUO#1p~iEL$Kby{bS3)0q0_$)cy9%d zeT{W)-x)lNjY-JgnB~JWUSrN=Ka&?Fc>Uq1KXhd^)(9+tnYCqFg5@*3M3dJWfoc&D z1L6k+#COy1xLGctMB}oBSG~qUhx2pNUscrdSAL9GJY$nf$9RE?mz~~*Af6&83#aCO z^k<^mQ6@J263hH^3U9xQb!|Tu$>D|m^A0==SQ^BK?qWk+Uf{VMLm{cx!#Z3BZx0`IGseQ7W(`DX2uI_EUa>d+Q^B8fGDV$Oz)p&Xh9#EAkrN&# zX!^%)$6-VZ$K;C0Om6IAj=^H%{b#==+?GEYa{2Yr7Q%4}zgvxIj999FQ26Xh7TR&w zGoBr-=$ISc=Q@LLu4Fy?%m%;6sTgZovl@&<@B1njfn^#2j>iCc!c_8!^8hI^^w1Gx8I z_ST>&j|(kFpz2NSjIk2*5bcnAIQce>Q0NYCBYiW<81M{l+KZ>#KR?awRV-}qEvF%z z7j?NNG0$n7hN_#od|=T8Q#|r6I{&`$4w&M*`X)btUVWNpA>DwxMX!7_s$DI{PZ8X! zjdy`zz9_m-L^X_(HE>6bz$(js+s6vLuPlb&`HuZ;8QZ(}>;3FK#uIDU;IIoTkq|HY z$q&CS7``j;a3xJTC~j%|a3wFR!B8q%D8Anro1;(5#m4`E3LKs+yU0jHRL*J>2EU=bh|DBb!e@)6^`m_CF^O4W`fHw zo362?-DyUgeyVK*v?0HxxTP`w0NT=0!-nxkYw;Yg<_Fg7s`^t5X`G0OeoypwqMiRT z}>FUX`WC7Kw+h)yIrm*^^@g+#Xz-9@yHXfx42 zhz2NPHskXeq7g)6iH?>Odt(MM77#5UdOy*fME4UtNc0TRzY)Da^fFOZe!s6Mor(4$ z8c#G?P?V3Kc{OXgfM_1k`-xT(ts;7q=;uTYqQ4UjP|f_pi1sCVBhgf%S)kEEMXQK$ zCsDx@*SGtXLeX2h#M~TXvCcEp#}vVY&2yHN0>3E+M8+myX;+6 zGmVG7V@kG6GbR0|o77I!Ni>#dB2oMrlFTQI=nA3*M2m@TBU)inm$Hi()kKdHJx;Wq zXamu2i5f(IB-%{$SE4OMl^JHm0*Ts*21$w@4kku-qE4cbM5BrJCmKt12+??=Hxb2) z+ENqAL^YzRMAM082r5QcCNbs^%_6#pXg1LmM01Gd5iKBkC(%Np8;KSZ-A1&M=q^x~ z7(vy3c=qaN3?p9XNGbmdK+vk}4 zSfU!y>^XZEoMc;lI#v*)fvEEq9`FhKAoJ!GYm!#T-*1NA=@RP!_&4V+UMx9;$1TpA zK7U2N$rBO8pW2o$x=-+V;VWv_z_A5F&b;>i^a=A~u7l^y`RrlazqlS}c$qDEg6JP4 z@1YGBO!?#{lQwwdhYT1WI0(R!la68({=C;wk1#!B)BMR+eT zHDM>}BpOXLo@g>rjc7X2ETRQOO`AYbiV2qy-A1%RP_dF#5@Q$9Dx%dyPZ4b(+Dz1M zp;=)k(O9Ay(R8AjM6-xy6U_mYD_H?C3W*jIEhD;(Xa&(qqE$ps5p5vqDWI9KvWPTG z)JZgc5v^nzF|vr}5xtXWG0_U5bwnG8y5%)$4AI(#Tg?KSi7MGt0iw&4`N{xgyppc) zb)U0gu4>{dOHH{%qJ>0H5sh7D#upN;CaNr_bVLh@Rui?aFynKGRui?al>BZ=v>8wm ziKY|XwsPbgIO&33Xbmle3csHDl)SbOPRR*2#dq7xa@@SxKLif zgoWQ(T+xKZdwSxEB`l5s;)*AXql~-~35&-<;&N%k2r#jdPPiT6Ou~VLvj|%WXA^Eu zIES!}Z~gdKz{33n#Ei!k28mRA*F zd{`o{YQpe0vBL-a2@;XIWxbVeQPZ-Y!VnT%0{!x zBLo(U$F4k+(US!HNC1zDocEXGnf?&cb;b_8MgyRW&6SmXxXd$doyvv6enZyu3 z>LRXe!s1OMaTO58udK<-vu?K|TukwSgtrm460RiNo^X|kU5bqubtE9(j1X5n;SPj7 z8$w6Io((~~gD5V8C&98P$fz@mSh#Hb{J9)zn1M-Z+f+>>xU;Yh*;;V8l_gnJS8yU)}>Z^FUA z(s<}YjA#<*OE{izKf)T}{)96L42`j~BixUXreHwYH8A;e#>@pdnh!INyiG&jgClO93Jce)<;bg)E zgvSytCVVsDZG^`Wu5=M2g&0+Y#}mezKeEOX2-g!%C2SC$NVtWt_-z7l`IVUI(+LL? zo6NgU^?6 z6~+4#t|J^kxSp{1x?5ZZVLRa#!kq~FZ8kL$B(a$P#OO={(S$5r#gCSn`#&)l*;v(ty$PQp>`SOq<2_%qCn2{BkMcAKk4&ea8 zg@gkMmk|yjTtPU2a1~+ZA}h0w82*Io2?r212!{}EA)G+iUP@i&lnPLsg#8J}5)L4o zNZ6G?jC4;1k!A*2o(u@*crqYdNH~FTnJ0a;nZCl4p71VDdcxHvb}6jCnc$Qs0pSKu z0>aINS*$6q+;6tnpRk>90AVL#HpG;V^~e)WloJSr!?eq*x{ENi(0@C|;ohiwEXVd_6G=3FFDDyvhjg zCR|}+mr_BDT_o@T;cCJs37;bTG2sTnX9zbFeu1#^lv&|@gzbb65_U?A_J2W)SQ7A@ z7ZM2{r}%Wj?-R}!bb?#6Ml%WL3lsm7Q%-J`&F3by+JtGMT}2~5l#3M zVZ6I&ns$UW!qtQ`37;jLPA&8&oK5kk2^SFllCZ0o7@rbj8{wmbD+#|zxQcKM;X1+} z5w0h^ldwVf6~ZlqzcR5)!G9JfTUbs4!Gs$KM-zUVFy6zI@*fh`2%jgMNf@t|$Sa%h z-v}2F{!C)bzhYv1Kmx%uk9!i{M)8XYr&GMgQ&LIsD=0pe;ys?1DvHmh_)O}e0D;B) zuOop}63C$pVhGn${2IbpltDYf2E{*2xP|bug#Dg2HTEjuV8Us@qI@Nq7;lk4JmGf; zdmIyR#mGye_+r8yPl?C1lS%P1bI4>|!5yCBmCwo*>ObP5H;P;H#XHy7gQ-uZ)4yO2A!o?Inh;TH;7Z5&0@i!8Vr+C*r z#3(B=3+zDH<9r%LSfd0bgfj_G^`xf)1{2Pv__c(iDL#sDff?^oZY7431R@C+QwB>2 zZzFs^;Y^b6N4S#WR}!uwTtwI)`4NQcWIXhLFEQ##Ai;wvgN=j>DL$64LGe!#ZXtXJ zVZWWGM)L^=6P`wRTM^<#|92!tGzn}ajF+F~N|!-cBg_d`hztj+nR;)`hi?@Ww( z638T6O%>=u*r52Cgc~-RExd_v3&n3D?Dwo0|2*Mf!nYHSe%56QJVA_8RA5)a@swaT zVLKHVL0F^sMT9d6zehNma4q2i!n+6;yNFRmjBSLE5w0YBm~cH+FobXw#m^xO^IndL zZwS{>`~kuZgx@9XY9YpRo(!HdGkDaKfC}tJIGW-gBOFio7Q)*|Lve&PieE?A?0*m=yK?MvE3|s~YJY_;fdEV@j^@QU| zzBl1uieE}Nn(%6mJYg@w8sV>jtiwVC-cpKrH30FSP_D=1r zTB7*3RjQq9i`A;V&fC=nd&sF(=Iag3L@QRCxG-mL-wf5K18*o%gEBq;-MNbV*5a=C zo+%aL%LH7WIAKeOb*uXiOzHmF^>Jd`--g7oh>L9#$8XZrm0ot$e4`>Tc#5f4C#ZPG z!od^YR_*wI!sqpyGBtVX+y^ZmmIOwR-TCNWL#po7YeX4iZk#i1&EniOb5`H682?#& z_UaXj_<{%2DWV(SrdycaLQ~_$WTYzC&nxg#V=;M)3-TgY$}v|lo+(bmdw7wtu}U>~ z;{P}|c?I&nPY)J&srY}QIlrcgs^Lja%HtRZGx=fo5o~(#Wo1TfJE~Vgl!Av1pcs);M zSbQBXLuOcZU4|J_t^z#eVN{U*Q+Y84qA`L^9Jy}Yx~nq)F-cb#_(BLYkP|HMt8TW2HHm1)kUxh&Q-= zvR5SEwpEQ({}{*L+p30SHe)8W7rXogru4w0s_wrIR{RzXl{^jnAi+npkhz9Y?Ytq% zb!j2f7W0g4>d?jE_&fvm6Cx9fs#t#Ym$(JImnmZr-xlv`lcsB!k78S7Rcu276fKfy~@T z)t)0qD$3Ki%bKVTa5n#+>?gC|EL<{@=+C^!D=iE^icwb1So-n z{c?P>eA0X1F<~&8XZhAoX`YNH##0o<`J#8`L!y3Au3aRGVkEzaXi7OOE{N_@HC&e|)pLtB};c~(j{u%d2B+wR{ z+QSRRQhWH>>sF28WnjPuJm{muXZR|yL;Muqd%SYgEJa~fU&T7w zzuC9J(+2Qv>8RY2?X6_~+D@7JZJ;voBdd~fu)UI$VN-?=u`2HZ>p1U3(n?^lJ9j=RqUCMX~Ggc{LKj!qvjI&*mT6KeNxe=CD(uBB>x2h$aI z5>j=07aw^)p@#D2C)Dh@%;Bdv@^CLg?+)=%9D_SFFg#7~jLF;iAzQjX%^XkpkDOMN zE4bGnr^GY(k0$V>--dLy!R>N9GBXjs0QbxZ{O2dt*?jU-YNwk#kzanMC_mtyi44Rg z8`!3*_kXDX zUL8G3`TQ4rPIO6j!0Q$2_*TB^!<4SLYbNmaJJbkQhkxqaT(qYc_vcjK4jufI4nsO9 z9dfPB?N0eu`{wwx4&0&sSh)k3((IA_Hv{2yJGJY7f)lVz*`*1l>Vu5!0`8lFQ;;!XVt!u|88=v z9m$k^xED}8bU{z2Ra zk&B=Vzl9+-5C4DDt6$=GXY45$d5{%U=GT#*?4ja6iRqzwyHKvu{dYuw2GCsvtFQsL zANb9=uqI%tB?@yb5B~`cXd&)c+zp5mn~>Pe20}I+_Z_&O#Jvmmaom@2hr?JLgL@8c zu~?~!m*TBh6dwieTKOsdeE#$5{oGNh4(xpE;=FkaSFaK$ih0?K=ik0|-kPQB7IRjq z207Zstyr43_*#^`ZB%Olo?NN+5{92JRz24i@hMHZ_-Ll{|Nn{A|F=J}3K3)C-+yAo zpL$8XyHi&cA7YHj&&^%DDla{E^}@w#*6?mGtLLq!y{F`@n6~PUrK=W=E#RTAs$B+5PF&v+e9jhsEIUkC9Xy3o+B)utzb@tQ4aC;nrV+TXjb1N;o) z!?XWpsK0kC{%=e3gS6OOGrwJHOxnE2{2*;ehb(w6#7u1nGU*r`=2D*j{VkQjZ(-xV z?^WO5Tk)nE>jfCZ^Ilhfb>W99+%ZTZ?zUHV6eqH(?E8O*y6AFJzAu~k_WK`=oquo? z)d9!%HrI04)Wk8R(MG-U%d-X>HP)zzCk^(fX(w%|6K#gMTE>ZO#B&DlRP@dt?cf;k z`a>>t==6S-?9F7{11*V&<5?IDQz$1!iwYVvwn1+s3Tlu9`}y9kHT|!d`R4Q8x9`1u zKX%{Vdzal9uK7Qhd~2IIJGr~Z^nF<+UEMpdxnS0KVzqq6&KmVaYnsiMDTjwe~wvZ96x=wIejLo8R->%RyT@7l8K{XytoUE z;!E(tIfiizAB1I8{T>B{pDi#9KVEI0Yhfh@Ux1(Td2gA*7cvvLlADJ77jw-2nSU}5 zjT!H-bC5`)aTQOzDgnF+9l%GRkGpOeUklIv5%J1=qJo-u*5jv7Ks7Nv@e?jV!o^FO zc!u!PC!Ly%cK(!qiCN}L0-4`j$Lx$q3Al*4<~k+#V$NBai;lBhAY5!<>bVm?ecGw% zXqsiPGU4JjWH4J}LC|>YR{jhH&!V7lM}*lRJ`NYeZlmegXo9aZaI`4_JeM1+YNi|S z?XK62_yyPNM*N}cbz|PYh8mG}`qWZW&ekaZ=#y}<1NGyl&m3c#Q%<4557nBx=h>U$mE4o}|ac;kMWobQ(Wq-}@S^F35EJ`6A74;ni0 zL3n?H{_kNUkzgA1sIwyipLmQ?6JCTzGE92$)U+H6f6#gD5?H}MC*O#Dos}nAsAs-`B1E$s8AzttLPPiTE%&*W5FGFL% z$w*v^RDm`)caXd&g!l|_sK=Nx?K4R-SP4ju?sAD6?_VPAAi5 z_$$|U!^O|j1;lBE4cW6>OJ%=J_=|2!#RKt&OvIGMmUNB#1TV#o%2TgHBx~J@Uj=3 z@P%*{igl4drfnaI@Ex%3C5CUjxExjb6+Z3yF_?Rq0~1H|yyC?1!iWCJrAv4ZoIpCT zXuisVHsM~l1Z~HMUgi3~kqy;g1-!@gaX9GuB0Pb{NH7WYvK4hl2;PTA2txgp!ze^}3LZo%HP0g(f%lwDc_!Jo%k{l**!AMlvJ)o^Z+@TI9{F@b7K)56ycZTe zU=YI(e!%tLbCd+fIAh_=W6tnd4L2eUz2ZF|bH67+94?;VawUE%JdQ>P=UHZ>^SDz1 zG3t78)+AR8aq8j2C`ekKg*JAf%J{zJKTWO1-)>@ z_2PVw6CQvoT_1tZA$99cIFD5V4MYLxt@0RM97~KX7;$>x-PIHxABP7~KxyF(Uv&=L3Hwmxo`9LmAhkWOST%WVBfE!rQ$G@QYhO#<;=q^5fSu0N9||Cj*;P9h~1 zfBX%nX3JnFuVJqxjyRLmH9vm(%9>W(UPn2?#RI5_|9rVFru90l+ttiwu)&K9&;$4; zXwGp8Dq@D-#A?1z7zN9~D|f-fS)8HP8{cUq-;KK;L) zjk-^0KDgpshGTp`ye&Xe;a9=KNQuiZdLB0^!o`{2;sYkW8m?@laQFy3eF0}Zz7Br< z0!~nTJ-q1Kj&FvWnrOKR`rpFzUC2p6Bnw{NOabr<;rpn0f<&98dj8XetPH4Q?gme>%$vlrH*)ar< zAm4Fn3@5H3GG3hjJ*RL1xCH4+3BjFcE^)-S-SAQP5mIHeym>~*@eS~H)JFUgJZmZa zzl@FWQfh#r+5wZ_r$z9*;l|h^PYdbmC4F@iCR0&g1Idf$T}wK=s4s375?|D6y5flX z8b)5!w+!;@uT}rM8{%`W7qzsnNTQbR<;Bz594~66UE!jZ&gDfd@yd&9T`y`WS>a;8 z{5&>fw3@3OqE>6=E339YkWU_Z$h>u+@UgjEYat6Z>@$aapT8S%>r3WQPx8<{^X%mK zKC?!@YPY^@ZZd0ba(+IKII#LPbCaj4=A71nMF-5kd$sIyi}H&mPn|HY@PNEaKFcZqOXSyg}?zJtuU=P|wd&oApvGWH9Ai2s@bzO3|r>etO>>KJU_3iIV z2F&BDZ@R|9;mN0dUXA+rIrjRLSN|})i^UiE-)}L+42D9zia5j>SXA{{}wva7mOWBd^ zc-F|(<_79cngP!Wqr??MC5)Vp!1|mq;%ra+rFK*OCc^oHh*l6zS*fAaSjv|Uq&w1) nbTl1L52lOhCh8ibw(Zn6OpPOzIwz=gih38QdC~fBzuom89zKm4 diff --git a/libs/runtimes/win-x64/libcryptonote.dll b/libs/runtimes/win-x64/libcryptonote.dll index 8d1a1fa94ba9206ace015b4774e98fc3f6163f47..5d73a4576f7ba16ff867cabf7ed46dd898d0d6b5 100644 GIT binary patch delta 163081 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උ_{e)m2 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

!g9=(W4UCWymF8?Q+^dt+?__xKDIRm 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≺%SN4_65w3GTsY0(XfgI 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 gMtgbt)Z{TO+n9#_jTIZcwSn5w+HIpgw40Lt8 headerHash = stackalloc byte[32]; - hashFunc(blobConverted, headerHash, variant); + hashFunc(blobConverted, headerHash, variant, BlockTemplate.Height); var headerHashString = headerHash.ToHexString(); if (headerHashString != workerHash) diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs index fc4c7ce43..26251c0b2 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs @@ -168,7 +168,8 @@ private CryptonoteJobParams CreateWorkerJob(StratumClient client) { JobId = job.Id, Blob = blob, - Target = target + Target = target, + Height = job.Height, }; // update context diff --git a/src/Miningcore/Blockchain/Cryptonote/StratumResponses/CryptonoteLoginResponse.cs b/src/Miningcore/Blockchain/Cryptonote/StratumResponses/CryptonoteLoginResponse.cs index 2e6720df9..3234ef078 100644 --- a/src/Miningcore/Blockchain/Cryptonote/StratumResponses/CryptonoteLoginResponse.cs +++ b/src/Miningcore/Blockchain/Cryptonote/StratumResponses/CryptonoteLoginResponse.cs @@ -29,6 +29,11 @@ public class CryptonoteJobParams public string Blob { get; set; } public string Target { get; set; } + + ///

+ /// Introduced for CNv4 (aka CryptonightR) + /// + public ulong Height { get; set; } } public class CryptonoteLoginResponse : CryptonoteResponseBase diff --git a/src/Miningcore/Native/LibCryptonight.cs b/src/Miningcore/Native/LibCryptonight.cs index 1089d9be7..c27451640 100644 --- a/src/Miningcore/Native/LibCryptonight.cs +++ b/src/Miningcore/Native/LibCryptonight.cs @@ -33,7 +33,7 @@ public static unsafe class LibCryptonight internal class CryptonightContextStore { - internal CryptonightContextStore(Func allocator, int allocationSize, string logId) + internal CryptonightContextStore(Func allocator, string logId) { this.logId = logId.ToUpper(); @@ -44,9 +44,6 @@ internal CryptonightContextStore(Func allocator, int allocationSize, str { var result = allocator(); - if(result != IntPtr.Zero) - GC.AddMemoryPressure(allocationSize); - return result; })); } @@ -73,23 +70,15 @@ internal void Return(Lazy ctx) } } - private static readonly CryptonightContextStore ctxs = new CryptonightContextStore(cryptonight_alloc_context, cryptonight_get_context_size(), "cn"); - private static readonly CryptonightContextStore ctxsLite = new CryptonightContextStore(cryptonight_alloc_lite_context, cryptonight_get_context_lite_size(), "cn-lite"); - private static readonly CryptonightContextStore ctxsHeavy = new CryptonightContextStore(cryptonight_alloc_heavy_context, cryptonight_get_context_heavy_size(), "cn-heavy"); + private static readonly CryptonightContextStore ctxs = new CryptonightContextStore(cryptonight_alloc_context, "cn"); + private static readonly CryptonightContextStore ctxsLite = new CryptonightContextStore(cryptonight_alloc_lite_context, "cn-lite"); + private static readonly CryptonightContextStore ctxsHeavy = new CryptonightContextStore(cryptonight_alloc_heavy_context, "cn-heavy"); + private static readonly CryptonightContextStore ctxsPico = new CryptonightContextStore(cryptonight_alloc_pico_context, "cn-pico"); #endregion // Hashing context managment private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); - [DllImport("libcryptonight", EntryPoint = "cryptonight_get_context_size_export", CallingConvention = CallingConvention.Cdecl)] - private static extern int cryptonight_get_context_size(); - - [DllImport("libcryptonight", EntryPoint = "cryptonight_get_context_lite_size_export", CallingConvention = CallingConvention.Cdecl)] - private static extern int cryptonight_get_context_lite_size(); - - [DllImport("libcryptonight", EntryPoint = "cryptonight_get_context_heavy_size_export", CallingConvention = CallingConvention.Cdecl)] - private static extern int cryptonight_get_context_heavy_size(); - [DllImport("libcryptonight", EntryPoint = "cryptonight_alloc_context_export", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr cryptonight_alloc_context(); @@ -97,21 +86,27 @@ internal void Return(Lazy ctx) private static extern IntPtr cryptonight_alloc_lite_context(); [DllImport("libcryptonight", EntryPoint = "cryptonight_alloc_heavy_context_export", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr cryptonight_alloc_heavy_context(); + private static extern IntPtr cryptonight_alloc_heavy_context(); + + [DllImport("libcryptonight", EntryPoint = "cryptonight_alloc_pico_context_export", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr cryptonight_alloc_pico_context(); [DllImport("libcryptonight", EntryPoint = "cryptonight_free_context_export", CallingConvention = CallingConvention.Cdecl)] private static extern void cryptonight_free_context(IntPtr ptr); [DllImport("libcryptonight", EntryPoint = "cryptonight_export", CallingConvention = CallingConvention.Cdecl)] - private static extern int cryptonight(IntPtr ctx, byte* input, byte* output, uint inputLength, CryptonightVariant variant); + private static extern int cryptonight(IntPtr ctx, byte* input, byte* output, uint inputLength, CryptonightVariant variant, ulong height); [DllImport("libcryptonight", EntryPoint = "cryptonight_light_export", CallingConvention = CallingConvention.Cdecl)] - private static extern int cryptonight_light(IntPtr ctx, byte* input, byte* output, uint inputLength, CryptonightVariant variant); + private static extern int cryptonight_light(IntPtr ctx, byte* input, byte* output, uint inputLength, CryptonightVariant variant, ulong height); [DllImport("libcryptonight", EntryPoint = "cryptonight_heavy_export", CallingConvention = CallingConvention.Cdecl)] - private static extern int cryptonight_heavy(IntPtr ctx, byte* input, byte* output, uint inputLength, CryptonightVariant variant); + private static extern int cryptonight_heavy(IntPtr ctx, byte* input, byte* output, uint inputLength, CryptonightVariant variant, ulong height); + + [DllImport("libcryptonight", EntryPoint = "cryptonight_pico_export", CallingConvention = CallingConvention.Cdecl)] + private static extern int cryptonight_pico(IntPtr ctx, byte* input, byte* output, uint inputLength, CryptonightVariant variant, ulong height); - public delegate void CryptonightHash(ReadOnlySpan data, Span result, CryptonightVariant variant); + public delegate void CryptonightHash(ReadOnlySpan data, Span result, CryptonightVariant variant, ulong height); // see https://github.com/xmrig/xmrig/blob/master/src/common/xmrig.h public enum CryptonightVariant @@ -126,14 +121,19 @@ public enum CryptonightVariant VARIANT_XAO = 6, // Modified CryptoNight variant 0 (Alloy only) VARIANT_RTO = 7, // Modified CryptoNight variant 1 (Arto only) VARIANT_2 = 8, // CryptoNight variant 2 - VARIANT_MAX + VARIANT_HALF = 9, // CryptoNight variant 2 with half iterations (Masari/Stellite) + VARIANT_TRTL = 10, // CryptoNight Turtle (TRTL) + VARIANT_GPU = 11, // CryptoNight-GPU (Ryo) + VARIANT_WOW = 12, // CryptoNightR (Wownero) + VARIANT_4 = 13, // CryptoNightR (Monero's variant 4) + VARIANT_MAX }; /// /// Cryptonight Hash (Monero, Monero v7, v8 etc.) /// /// Algorithm variant - public static void Cryptonight(ReadOnlySpan data, Span result, CryptonightVariant variant) + public static void Cryptonight(ReadOnlySpan data, Span result, CryptonightVariant variant, ulong height) { Contract.Requires(result.Length >= 32, $"{nameof(result)} must be greater or equal 32 bytes"); @@ -145,7 +145,7 @@ public static void Cryptonight(ReadOnlySpan data, Span result, Crypt { fixed (byte* output = result) { - cryptonight(ctx.Value, input, output, (uint)data.Length, variant); + cryptonight(ctx.Value, input, output, (uint)data.Length, variant, height); } } } @@ -160,7 +160,7 @@ public static void Cryptonight(ReadOnlySpan data, Span result, Crypt /// Cryptonight Lite Hash (AEON etc.) /// /// Algorithm variant - public static void CryptonightLight(ReadOnlySpan data, Span result, CryptonightVariant variant) + public static void CryptonightLight(ReadOnlySpan data, Span result, CryptonightVariant variant, ulong height) { Contract.Requires(result.Length >= 32, $"{nameof(result)} must be greater or equal 32 bytes"); @@ -172,7 +172,7 @@ public static void CryptonightLight(ReadOnlySpan data, Span result, { fixed(byte* output = result) { - cryptonight_light(ctx.Value, input, output, (uint) data.Length, variant); + cryptonight_light(ctx.Value, input, output, (uint) data.Length, variant, height); } } } @@ -187,7 +187,7 @@ public static void CryptonightLight(ReadOnlySpan data, Span result, /// Cryptonight Heavy Hash (TUBE etc.) /// /// Algorithm variant - public static void CryptonightHeavy(ReadOnlySpan data, Span result, CryptonightVariant variant) + public static void CryptonightHeavy(ReadOnlySpan data, Span result, CryptonightVariant variant, ulong height) { Contract.Requires(result.Length >= 32, $"{nameof(result)} must be greater or equal 32 bytes"); @@ -199,7 +199,7 @@ public static void CryptonightHeavy(ReadOnlySpan data, Span result, { fixed (byte* output = result) { - cryptonight_heavy(ctx.Value, input, output, (uint) data.Length, variant); + cryptonight_heavy(ctx.Value, input, output, (uint) data.Length, variant, height); } } } @@ -209,5 +209,32 @@ public static void CryptonightHeavy(ReadOnlySpan data, Span result, ctxsHeavy.Return(ctx); } } + + /// + /// Cryptonight Pico Hash (TUBE etc.) + /// + /// Algorithm variant + public static void CryptonightPico(ReadOnlySpan data, Span result, CryptonightVariant variant, ulong height) + { + Contract.Requires(result.Length >= 32, $"{nameof(result)} must be greater or equal 32 bytes"); + + var ctx = ctxsPico.Lease(); + + try + { + fixed (byte* input = data) + { + fixed (byte* output = result) + { + cryptonight_pico(ctx.Value, input, output, (uint)data.Length, variant, height); + } + } + } + + finally + { + ctxsPico.Return(ctx); + } + } } } diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/allocators.h b/src/Native/libcryptonight/3rdparty/rapidjson/allocators.h deleted file mode 100644 index 98affe03f..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/allocators.h +++ /dev/null @@ -1,271 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ALLOCATORS_H_ -#define RAPIDJSON_ALLOCATORS_H_ - -#include "rapidjson.h" - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// Allocator - -/*! \class rapidjson::Allocator - \brief Concept for allocating, resizing and freeing memory block. - - Note that Malloc() and Realloc() are non-static but Free() is static. - - So if an allocator need to support Free(), it needs to put its pointer in - the header of memory block. - -\code -concept Allocator { - static const bool kNeedFree; //!< Whether this allocator needs to call Free(). - - // Allocate a memory block. - // \param size of the memory block in bytes. - // \returns pointer to the memory block. - void* Malloc(size_t size); - - // Resize a memory block. - // \param originalPtr The pointer to current memory block. Null pointer is permitted. - // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) - // \param newSize the new size in bytes. - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); - - // Free a memory block. - // \param pointer to the memory block. Null pointer is permitted. - static void Free(void *ptr); -}; -\endcode -*/ - -/////////////////////////////////////////////////////////////////////////////// -// CrtAllocator - -//! C-runtime library allocator. -/*! This class is just wrapper for standard C library memory routines. - \note implements Allocator concept -*/ -class CrtAllocator { -public: - static const bool kNeedFree = true; - void* Malloc(size_t size) { - if (size) // behavior of malloc(0) is implementation defined. - return std::malloc(size); - else - return NULL; // standardize to returning NULL. - } - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { - (void)originalSize; - if (newSize == 0) { - std::free(originalPtr); - return NULL; - } - return std::realloc(originalPtr, newSize); - } - static void Free(void *ptr) { std::free(ptr); } -}; - -/////////////////////////////////////////////////////////////////////////////// -// MemoryPoolAllocator - -//! Default memory allocator used by the parser and DOM. -/*! This allocator allocate memory blocks from pre-allocated memory chunks. - - It does not free memory blocks. And Realloc() only allocate new memory. - - The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. - - User may also supply a buffer as the first chunk. - - If the user-buffer is full then additional chunks are allocated by BaseAllocator. - - The user-buffer is not deallocated by this allocator. - - \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. - \note implements Allocator concept -*/ -template -class MemoryPoolAllocator { -public: - static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) - - //! Constructor with chunkSize. - /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. - \param baseAllocator The allocator for allocating memory chunks. - */ - MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : - chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) - { - } - - //! Constructor with user-supplied buffer. - /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. - - The user buffer will not be deallocated when this allocator is destructed. - - \param buffer User supplied buffer. - \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). - \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. - \param baseAllocator The allocator for allocating memory chunks. - */ - MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : - chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) - { - RAPIDJSON_ASSERT(buffer != 0); - RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); - chunkHead_ = reinterpret_cast(buffer); - chunkHead_->capacity = size - sizeof(ChunkHeader); - chunkHead_->size = 0; - chunkHead_->next = 0; - } - - //! Destructor. - /*! This deallocates all memory chunks, excluding the user-supplied buffer. - */ - ~MemoryPoolAllocator() { - Clear(); - RAPIDJSON_DELETE(ownBaseAllocator_); - } - - //! Deallocates all memory chunks, excluding the user-supplied buffer. - void Clear() { - while (chunkHead_ && chunkHead_ != userBuffer_) { - ChunkHeader* next = chunkHead_->next; - baseAllocator_->Free(chunkHead_); - chunkHead_ = next; - } - if (chunkHead_ && chunkHead_ == userBuffer_) - chunkHead_->size = 0; // Clear user buffer - } - - //! Computes the total capacity of allocated memory chunks. - /*! \return total capacity in bytes. - */ - size_t Capacity() const { - size_t capacity = 0; - for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) - capacity += c->capacity; - return capacity; - } - - //! Computes the memory blocks allocated. - /*! \return total used bytes. - */ - size_t Size() const { - size_t size = 0; - for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) - size += c->size; - return size; - } - - //! Allocates a memory block. (concept Allocator) - void* Malloc(size_t size) { - if (!size) - return NULL; - - size = RAPIDJSON_ALIGN(size); - if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) - if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) - return NULL; - - void *buffer = reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; - chunkHead_->size += size; - return buffer; - } - - //! Resizes a memory block (concept Allocator) - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { - if (originalPtr == 0) - return Malloc(newSize); - - if (newSize == 0) - return NULL; - - originalSize = RAPIDJSON_ALIGN(originalSize); - newSize = RAPIDJSON_ALIGN(newSize); - - // Do not shrink if new size is smaller than original - if (originalSize >= newSize) - return originalPtr; - - // Simply expand it if it is the last allocation and there is sufficient space - if (originalPtr == reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { - size_t increment = static_cast(newSize - originalSize); - if (chunkHead_->size + increment <= chunkHead_->capacity) { - chunkHead_->size += increment; - return originalPtr; - } - } - - // Realloc process: allocate and copy memory, do not free original buffer. - if (void* newBuffer = Malloc(newSize)) { - if (originalSize) - std::memcpy(newBuffer, originalPtr, originalSize); - return newBuffer; - } - else - return NULL; - } - - //! Frees a memory block (concept Allocator) - static void Free(void *ptr) { (void)ptr; } // Do nothing - -private: - //! Copy constructor is not permitted. - MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; - //! Copy assignment operator is not permitted. - MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; - - //! Creates a new chunk. - /*! \param capacity Capacity of the chunk in bytes. - \return true if success. - */ - bool AddChunk(size_t capacity) { - if (!baseAllocator_) - ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); - if (ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { - chunk->capacity = capacity; - chunk->size = 0; - chunk->next = chunkHead_; - chunkHead_ = chunk; - return true; - } - else - return false; - } - - static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. - - //! Chunk header for perpending to each chunk. - /*! Chunks are stored as a singly linked list. - */ - struct ChunkHeader { - size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). - size_t size; //!< Current size of allocated memory in bytes. - ChunkHeader *next; //!< Next chunk in the linked list. - }; - - ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. - size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. - void *userBuffer_; //!< User supplied buffer. - BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. - BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. -}; - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/document.h b/src/Native/libcryptonight/3rdparty/rapidjson/document.h deleted file mode 100644 index e3e20dfbd..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/document.h +++ /dev/null @@ -1,2575 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_DOCUMENT_H_ -#define RAPIDJSON_DOCUMENT_H_ - -/*! \file document.h */ - -#include "reader.h" -#include "internal/meta.h" -#include "internal/strfunc.h" -#include "memorystream.h" -#include "encodedstream.h" -#include // placement new -#include - -RAPIDJSON_DIAG_PUSH -#ifdef _MSC_VER -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(switch-enum) -RAPIDJSON_DIAG_OFF(c++98-compat) -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_OFF(effc++) -#if __GNUC__ >= 6 -RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions -#endif -#endif // __GNUC__ - -#ifndef RAPIDJSON_NOMEMBERITERATORCLASS -#include // std::iterator, std::random_access_iterator_tag -#endif - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS -#include // std::move -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -// Forward declaration. -template -class GenericValue; - -template -class GenericDocument; - -//! Name-value pair in a JSON object value. -/*! - This class was internal to GenericValue. It used to be a inner struct. - But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. - https://code.google.com/p/rapidjson/issues/detail?id=64 -*/ -template -struct GenericMember { - GenericValue name; //!< name of member (must be a string) - GenericValue value; //!< value of member. -}; - -/////////////////////////////////////////////////////////////////////////////// -// GenericMemberIterator - -#ifndef RAPIDJSON_NOMEMBERITERATORCLASS - -//! (Constant) member iterator for a JSON object value -/*! - \tparam Const Is this a constant iterator? - \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) - \tparam Allocator Allocator type for allocating memory of object, array and string. - - This class implements a Random Access Iterator for GenericMember elements - of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. - - \note This iterator implementation is mainly intended to avoid implicit - conversions from iterator values to \c NULL, - e.g. from GenericValue::FindMember. - - \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a - pointer-based implementation, if your platform doesn't provide - the C++ header. - - \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator - */ -template -class GenericMemberIterator - : public std::iterator >::Type> { - - friend class GenericValue; - template friend class GenericMemberIterator; - - typedef GenericMember PlainType; - typedef typename internal::MaybeAddConst::Type ValueType; - typedef std::iterator BaseType; - -public: - //! Iterator type itself - typedef GenericMemberIterator Iterator; - //! Constant iterator type - typedef GenericMemberIterator ConstIterator; - //! Non-constant iterator type - typedef GenericMemberIterator NonConstIterator; - - //! Pointer to (const) GenericMember - typedef typename BaseType::pointer Pointer; - //! Reference to (const) GenericMember - typedef typename BaseType::reference Reference; - //! Signed integer type (e.g. \c ptrdiff_t) - typedef typename BaseType::difference_type DifferenceType; - - //! Default constructor (singular value) - /*! Creates an iterator pointing to no element. - \note All operations, except for comparisons, are undefined on such values. - */ - GenericMemberIterator() : ptr_() {} - - //! Iterator conversions to more const - /*! - \param it (Non-const) iterator to copy from - - Allows the creation of an iterator from another GenericMemberIterator - that is "less const". Especially, creating a non-constant iterator - from a constant iterator are disabled: - \li const -> non-const (not ok) - \li const -> const (ok) - \li non-const -> const (ok) - \li non-const -> non-const (ok) - - \note If the \c Const template parameter is already \c false, this - constructor effectively defines a regular copy-constructor. - Otherwise, the copy constructor is implicitly defined. - */ - GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} - Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; } - - //! @name stepping - //@{ - Iterator& operator++(){ ++ptr_; return *this; } - Iterator& operator--(){ --ptr_; return *this; } - Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } - Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } - //@} - - //! @name increment/decrement - //@{ - Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } - Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } - - Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } - Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } - //@} - - //! @name relations - //@{ - bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; } - bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; } - bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; } - bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; } - bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; } - bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; } - //@} - - //! @name dereference - //@{ - Reference operator*() const { return *ptr_; } - Pointer operator->() const { return ptr_; } - Reference operator[](DifferenceType n) const { return ptr_[n]; } - //@} - - //! Distance - DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; } - -private: - //! Internal constructor from plain pointer - explicit GenericMemberIterator(Pointer p) : ptr_(p) {} - - Pointer ptr_; //!< raw pointer -}; - -#else // RAPIDJSON_NOMEMBERITERATORCLASS - -// class-based member iterator implementation disabled, use plain pointers - -template -struct GenericMemberIterator; - -//! non-const GenericMemberIterator -template -struct GenericMemberIterator { - //! use plain pointer as iterator type - typedef GenericMember* Iterator; -}; -//! const GenericMemberIterator -template -struct GenericMemberIterator { - //! use plain const pointer as iterator type - typedef const GenericMember* Iterator; -}; - -#endif // RAPIDJSON_NOMEMBERITERATORCLASS - -/////////////////////////////////////////////////////////////////////////////// -// GenericStringRef - -//! Reference to a constant string (not taking a copy) -/*! - \tparam CharType character type of the string - - This helper class is used to automatically infer constant string - references for string literals, especially from \c const \b (!) - character arrays. - - The main use is for creating JSON string values without copying the - source string via an \ref Allocator. This requires that the referenced - string pointers have a sufficient lifetime, which exceeds the lifetime - of the associated GenericValue. - - \b Example - \code - Value v("foo"); // ok, no need to copy & calculate length - const char foo[] = "foo"; - v.SetString(foo); // ok - - const char* bar = foo; - // Value x(bar); // not ok, can't rely on bar's lifetime - Value x(StringRef(bar)); // lifetime explicitly guaranteed by user - Value y(StringRef(bar, 3)); // ok, explicitly pass length - \endcode - - \see StringRef, GenericValue::SetString -*/ -template -struct GenericStringRef { - typedef CharType Ch; //!< character type of the string - - //! Create string reference from \c const character array -#ifndef __clang__ // -Wdocumentation - /*! - This constructor implicitly creates a constant string reference from - a \c const character array. It has better performance than - \ref StringRef(const CharType*) by inferring the string \ref length - from the array length, and also supports strings containing null - characters. - - \tparam N length of the string, automatically inferred - - \param str Constant character array, lifetime assumed to be longer - than the use of the string in e.g. a GenericValue - - \post \ref s == str - - \note Constant complexity. - \note There is a hidden, private overload to disallow references to - non-const character arrays to be created via this constructor. - By this, e.g. function-scope arrays used to be filled via - \c snprintf are excluded from consideration. - In such cases, the referenced string should be \b copied to the - GenericValue instead. - */ -#endif - template - GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT - : s(str), length(N-1) {} - - //! Explicitly create string reference from \c const character pointer -#ifndef __clang__ // -Wdocumentation - /*! - This constructor can be used to \b explicitly create a reference to - a constant string pointer. - - \see StringRef(const CharType*) - - \param str Constant character pointer, lifetime assumed to be longer - than the use of the string in e.g. a GenericValue - - \post \ref s == str - - \note There is a hidden, private overload to disallow references to - non-const character arrays to be created via this constructor. - By this, e.g. function-scope arrays used to be filled via - \c snprintf are excluded from consideration. - In such cases, the referenced string should be \b copied to the - GenericValue instead. - */ -#endif - explicit GenericStringRef(const CharType* str) - : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); } - - //! Create constant string reference from pointer and length -#ifndef __clang__ // -Wdocumentation - /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \param len length of the string, excluding the trailing NULL terminator - - \post \ref s == str && \ref length == len - \note Constant complexity. - */ -#endif - GenericStringRef(const CharType* str, SizeType len) - : s(str), length(len) { RAPIDJSON_ASSERT(s != 0); } - - GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} - - GenericStringRef& operator=(const GenericStringRef& rhs) { s = rhs.s; length = rhs.length; } - - //! implicit conversion to plain CharType pointer - operator const Ch *() const { return s; } - - const Ch* const s; //!< plain CharType pointer - const SizeType length; //!< length of the string (excluding the trailing NULL terminator) - -private: - //! Disallow construction from non-const array - template - GenericStringRef(CharType (&str)[N]) /* = delete */; -}; - -//! Mark a character pointer as constant string -/*! Mark a plain character pointer as a "string literal". This function - can be used to avoid copying a character string to be referenced as a - value in a JSON GenericValue object, if the string's lifetime is known - to be valid long enough. - \tparam CharType Character type of the string - \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \return GenericStringRef string reference object - \relatesalso GenericStringRef - - \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember -*/ -template -inline GenericStringRef StringRef(const CharType* str) { - return GenericStringRef(str, internal::StrLen(str)); -} - -//! Mark a character pointer as constant string -/*! Mark a plain character pointer as a "string literal". This function - can be used to avoid copying a character string to be referenced as a - value in a JSON GenericValue object, if the string's lifetime is known - to be valid long enough. - - This version has better performance with supplied length, and also - supports string containing null characters. - - \tparam CharType character type of the string - \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \param length The length of source string. - \return GenericStringRef string reference object - \relatesalso GenericStringRef -*/ -template -inline GenericStringRef StringRef(const CharType* str, size_t length) { - return GenericStringRef(str, SizeType(length)); -} - -#if RAPIDJSON_HAS_STDSTRING -//! Mark a string object as constant string -/*! Mark a string object (e.g. \c std::string) as a "string literal". - This function can be used to avoid copying a string to be referenced as a - value in a JSON GenericValue object, if the string's lifetime is known - to be valid long enough. - - \tparam CharType character type of the string - \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \return GenericStringRef string reference object - \relatesalso GenericStringRef - \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. -*/ -template -inline GenericStringRef StringRef(const std::basic_string& str) { - return GenericStringRef(str.data(), SizeType(str.size())); -} -#endif - -/////////////////////////////////////////////////////////////////////////////// -// GenericValue type traits -namespace internal { - -template -struct IsGenericValueImpl : FalseType {}; - -// select candidates according to nested encoding and allocator types -template struct IsGenericValueImpl::Type, typename Void::Type> - : IsBaseOf, T>::Type {}; - -// helper to match arbitrary GenericValue instantiations, including derived classes -template struct IsGenericValue : IsGenericValueImpl::Type {}; - -} // namespace internal - -/////////////////////////////////////////////////////////////////////////////// -// TypeHelper - -namespace internal { - -template -struct TypeHelper {}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsBool(); } - static bool Get(const ValueType& v) { return v.GetBool(); } - static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } - static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsInt(); } - static int Get(const ValueType& v) { return v.GetInt(); } - static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } - static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsUint(); } - static unsigned Get(const ValueType& v) { return v.GetUint(); } - static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); } - static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsInt64(); } - static int64_t Get(const ValueType& v) { return v.GetInt64(); } - static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); } - static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsUint64(); } - static uint64_t Get(const ValueType& v) { return v.GetUint64(); } - static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); } - static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsDouble(); } - static double Get(const ValueType& v) { return v.GetDouble(); } - static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); } - static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); } -}; - -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsFloat(); } - static float Get(const ValueType& v) { return v.GetFloat(); } - static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } - static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); } -}; - -template -struct TypeHelper { - typedef const typename ValueType::Ch* StringType; - static bool Is(const ValueType& v) { return v.IsString(); } - static StringType Get(const ValueType& v) { return v.GetString(); } - static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); } - static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } -}; - -#if RAPIDJSON_HAS_STDSTRING -template -struct TypeHelper > { - typedef std::basic_string StringType; - static bool Is(const ValueType& v) { return v.IsString(); } - static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); } - static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } -}; -#endif - -template -struct TypeHelper { - typedef typename ValueType::Array ArrayType; - static bool Is(const ValueType& v) { return v.IsArray(); } - static ArrayType Get(ValueType& v) { return v.GetArray(); } - static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } - static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; } -}; - -template -struct TypeHelper { - typedef typename ValueType::ConstArray ArrayType; - static bool Is(const ValueType& v) { return v.IsArray(); } - static ArrayType Get(const ValueType& v) { return v.GetArray(); } -}; - -template -struct TypeHelper { - typedef typename ValueType::Object ObjectType; - static bool Is(const ValueType& v) { return v.IsObject(); } - static ObjectType Get(ValueType& v) { return v.GetObject(); } - static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } - static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; } -}; - -template -struct TypeHelper { - typedef typename ValueType::ConstObject ObjectType; - static bool Is(const ValueType& v) { return v.IsObject(); } - static ObjectType Get(const ValueType& v) { return v.GetObject(); } -}; - -} // namespace internal - -// Forward declarations -template class GenericArray; -template class GenericObject; - -/////////////////////////////////////////////////////////////////////////////// -// GenericValue - -//! Represents a JSON value. Use Value for UTF8 encoding and default allocator. -/*! - A JSON value can be one of 7 types. This class is a variant type supporting - these types. - - Use the Value if UTF8 and default allocator - - \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) - \tparam Allocator Allocator type for allocating memory of object, array and string. -*/ -template > -class GenericValue { -public: - //! Name-value pair in an object. - typedef GenericMember Member; - typedef Encoding EncodingType; //!< Encoding type from template parameter. - typedef Allocator AllocatorType; //!< Allocator type from template parameter. - typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. - typedef GenericStringRef StringRefType; //!< Reference to a constant string - typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object. - typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. - typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. - typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. - typedef GenericValue ValueType; //!< Value type of itself. - typedef GenericArray Array; - typedef GenericArray ConstArray; - typedef GenericObject Object; - typedef GenericObject ConstObject; - - //!@name Constructors and destructor. - //@{ - - //! Default constructor creates a null value. - GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move constructor in C++11 - GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) { - rhs.data_.f.flags = kNullFlag; // give up contents - } -#endif - -private: - //! Copy constructor is not permitted. - GenericValue(const GenericValue& rhs); - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Moving from a GenericDocument is not permitted. - template - GenericValue(GenericDocument&& rhs); - - //! Move assignment from a GenericDocument is not permitted. - template - GenericValue& operator=(GenericDocument&& rhs); -#endif - -public: - - //! Constructor with JSON value type. - /*! This creates a Value of specified type with default content. - \param type Type of the value. - \note Default content for number is zero. - */ - explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() { - static const uint16_t defaultFlags[7] = { - kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, - kNumberAnyFlag - }; - RAPIDJSON_ASSERT(type <= kNumberType); - data_.f.flags = defaultFlags[type]; - - // Use ShortString to store empty string. - if (type == kStringType) - data_.ss.SetLength(0); - } - - //! Explicit copy constructor (with allocator) - /*! Creates a copy of a Value by using the given Allocator - \tparam SourceAllocator allocator of \c rhs - \param rhs Value to copy from (read-only) - \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). - \see CopyFrom() - */ - template< typename SourceAllocator > - GenericValue(const GenericValue& rhs, Allocator & allocator); - - //! Constructor for boolean value. - /*! \param b Boolean value - \note This constructor is limited to \em real boolean values and rejects - implicitly converted types like arbitrary pointers. Use an explicit cast - to \c bool, if you want to construct a boolean JSON value in such cases. - */ -#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen - template - explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) RAPIDJSON_NOEXCEPT // See #472 -#else - explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT -#endif - : data_() { - // safe-guard against failing SFINAE - RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); - data_.f.flags = b ? kTrueFlag : kFalseFlag; - } - - //! Constructor for int value. - explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() { - data_.n.i64 = i; - data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag; - } - - //! Constructor for unsigned value. - explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() { - data_.n.u64 = u; - data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag); - } - - //! Constructor for int64_t value. - explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() { - data_.n.i64 = i64; - data_.f.flags = kNumberInt64Flag; - if (i64 >= 0) { - data_.f.flags |= kNumberUint64Flag; - if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) - data_.f.flags |= kUintFlag; - if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - data_.f.flags |= kIntFlag; - } - else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - data_.f.flags |= kIntFlag; - } - - //! Constructor for uint64_t value. - explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() { - data_.n.u64 = u64; - data_.f.flags = kNumberUint64Flag; - if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) - data_.f.flags |= kInt64Flag; - if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) - data_.f.flags |= kUintFlag; - if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - data_.f.flags |= kIntFlag; - } - - //! Constructor for double value. - explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } - - //! Constructor for constant string (i.e. do not make a copy of string) - GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } - - //! Constructor for constant string (i.e. do not make a copy of string) - explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); } - - //! Constructor for copy-string (i.e. do make a copy of string) - GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); } - - //! Constructor for copy-string (i.e. do make a copy of string) - GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } - -#if RAPIDJSON_HAS_STDSTRING - //! Constructor for copy-string from a string object (i.e. do make a copy of string) - /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. - */ - GenericValue(const std::basic_string& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } -#endif - - //! Constructor for Array. - /*! - \param a An array obtained by \c GetArray(). - \note \c Array is always pass-by-value. - \note the source array is moved into this value and the sourec array becomes empty. - */ - GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { - a.value_.data_ = Data(); - a.value_.data_.f.flags = kArrayFlag; - } - - //! Constructor for Object. - /*! - \param o An object obtained by \c GetObject(). - \note \c Object is always pass-by-value. - \note the source object is moved into this value and the sourec object becomes empty. - */ - GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { - o.value_.data_ = Data(); - o.value_.data_.f.flags = kObjectFlag; - } - - //! Destructor. - /*! Need to destruct elements of array, members of object, or copy-string. - */ - ~GenericValue() { - if (Allocator::kNeedFree) { // Shortcut by Allocator's trait - switch(data_.f.flags) { - case kArrayFlag: - { - GenericValue* e = GetElementsPointer(); - for (GenericValue* v = e; v != e + data_.a.size; ++v) - v->~GenericValue(); - Allocator::Free(e); - } - break; - - case kObjectFlag: - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - Allocator::Free(GetMembersPointer()); - break; - - case kCopyStringFlag: - Allocator::Free(const_cast(GetStringPointer())); - break; - - default: - break; // Do nothing for other types. - } - } - } - - //@} - - //!@name Assignment operators - //@{ - - //! Assignment with move semantics. - /*! \param rhs Source of the assignment. It will become a null value after assignment. - */ - GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { - RAPIDJSON_ASSERT(this != &rhs); - this->~GenericValue(); - RawAssign(rhs); - return *this; - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move assignment in C++11 - GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT { - return *this = rhs.Move(); - } -#endif - - //! Assignment of constant string reference (no copy) - /*! \param str Constant string reference to be assigned - \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. - \see GenericStringRef, operator=(T) - */ - GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT { - GenericValue s(str); - return *this = s; - } - - //! Assignment with primitive types. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param value The value to be assigned. - - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref SetString(const Ch*, Allocator&) (for copying) or - \ref StringRef() (to explicitly mark the pointer as constant) instead. - All other pointer types would implicitly convert to \c bool, - use \ref SetBool() instead. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) - operator=(T value) { - GenericValue v(value); - return *this = v; - } - - //! Deep-copy assignment from Value - /*! Assigns a \b copy of the Value to the current Value object - \tparam SourceAllocator Allocator type of \c rhs - \param rhs Value to copy from (read-only) - \param allocator Allocator to use for copying - */ - template - GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator) { - RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); - this->~GenericValue(); - new (this) GenericValue(rhs, allocator); - return *this; - } - - //! Exchange the contents of this value with those of other. - /*! - \param other Another value. - \note Constant complexity. - */ - GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { - GenericValue temp; - temp.RawAssign(*this); - RawAssign(other); - other.RawAssign(temp); - return *this; - } - - //! free-standing swap function helper - /*! - Helper function to enable support for common swap implementation pattern based on \c std::swap: - \code - void swap(MyClass& a, MyClass& b) { - using std::swap; - swap(a.value, b.value); - // ... - } - \endcode - \see Swap() - */ - friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } - - //! Prepare Value for move semantics - /*! \return *this */ - GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } - //@} - - //!@name Equal-to and not-equal-to operators - //@{ - //! Equal-to operator - /*! - \note If an object contains duplicated named member, comparing equality with any object is always \c false. - \note Linear time complexity (number of all values in the subtree and total lengths of all strings). - */ - template - bool operator==(const GenericValue& rhs) const { - typedef GenericValue RhsType; - if (GetType() != rhs.GetType()) - return false; - - switch (GetType()) { - case kObjectType: // Warning: O(n^2) inner-loop - if (data_.o.size != rhs.data_.o.size) - return false; - for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { - typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); - if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) - return false; - } - return true; - - case kArrayType: - if (data_.a.size != rhs.data_.a.size) - return false; - for (SizeType i = 0; i < data_.a.size; i++) - if ((*this)[i] != rhs[i]) - return false; - return true; - - case kStringType: - return StringEqual(rhs); - - case kNumberType: - if (IsDouble() || rhs.IsDouble()) { - double a = GetDouble(); // May convert from integer to double. - double b = rhs.GetDouble(); // Ditto - return a >= b && a <= b; // Prevent -Wfloat-equal - } - else - return data_.n.u64 == rhs.data_.n.u64; - - default: - return true; - } - } - - //! Equal-to operator with const C-string pointer - bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } - -#if RAPIDJSON_HAS_STDSTRING - //! Equal-to operator with string object - /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. - */ - bool operator==(const std::basic_string& rhs) const { return *this == GenericValue(StringRef(rhs)); } -#endif - - //! Equal-to operator with primitive types - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false - */ - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } - - //! Not-equal-to operator - /*! \return !(*this == rhs) - */ - template - bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } - - //! Not-equal-to operator with const C-string pointer - bool operator!=(const Ch* rhs) const { return !(*this == rhs); } - - //! Not-equal-to operator with arbitrary types - /*! \return !(*this == rhs) - */ - template RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } - - //! Equal-to operator with arbitrary types (symmetric version) - /*! \return (rhs == lhs) - */ - template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } - - //! Not-Equal-to operator with arbitrary types (symmetric version) - /*! \return !(rhs == lhs) - */ - template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } - //@} - - //!@name Type - //@{ - - Type GetType() const { return static_cast(data_.f.flags & kTypeMask); } - bool IsNull() const { return data_.f.flags == kNullFlag; } - bool IsFalse() const { return data_.f.flags == kFalseFlag; } - bool IsTrue() const { return data_.f.flags == kTrueFlag; } - bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; } - bool IsObject() const { return data_.f.flags == kObjectFlag; } - bool IsArray() const { return data_.f.flags == kArrayFlag; } - bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; } - bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; } - bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; } - bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; } - bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; } - bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; } - bool IsString() const { return (data_.f.flags & kStringFlag) != 0; } - - // Checks whether a number can be losslessly converted to a double. - bool IsLosslessDouble() const { - if (!IsNumber()) return false; - if (IsUint64()) { - uint64_t u = GetUint64(); - volatile double d = static_cast(u); - return (d >= 0.0) - && (d < static_cast(std::numeric_limits::max())) - && (u == static_cast(d)); - } - if (IsInt64()) { - int64_t i = GetInt64(); - volatile double d = static_cast(i); - return (d >= static_cast(std::numeric_limits::min())) - && (d < static_cast(std::numeric_limits::max())) - && (i == static_cast(d)); - } - return true; // double, int, uint are always lossless - } - - // Checks whether a number is a float (possible lossy). - bool IsFloat() const { - if ((data_.f.flags & kDoubleFlag) == 0) - return false; - double d = GetDouble(); - return d >= -3.4028234e38 && d <= 3.4028234e38; - } - // Checks whether a number can be losslessly converted to a float. - bool IsLosslessFloat() const { - if (!IsNumber()) return false; - double a = GetDouble(); - if (a < static_cast(-std::numeric_limits::max()) - || a > static_cast(std::numeric_limits::max())) - return false; - double b = static_cast(static_cast(a)); - return a >= b && a <= b; // Prevent -Wfloat-equal - } - - //@} - - //!@name Null - //@{ - - GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } - - //@} - - //!@name Bool - //@{ - - bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; } - //!< Set boolean value - /*! \post IsBool() == true */ - GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } - - //@} - - //!@name Object - //@{ - - //! Set this value as an empty object. - /*! \post IsObject() == true */ - GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } - - //! Get the number of members in the object. - SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } - - //! Check whether the object is empty. - bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } - - //! Get a value from an object associated with the name. - /*! \pre IsObject() == true - \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType)) - \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. - Since 0.2, if the name is not correct, it will assert. - If user is unsure whether a member exists, user should use HasMember() first. - A better approach is to use FindMember(). - \note Linear time complexity. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(GenericValue&)) operator[](T* name) { - GenericValue n(StringRef(name)); - return (*this)[n]; - } - template - RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast(*this)[name]; } - - //! Get a value from an object associated with the name. - /*! \pre IsObject() == true - \tparam SourceAllocator Allocator of the \c name value - - \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen(). - And it can also handle strings with embedded null characters. - - \note Linear time complexity. - */ - template - GenericValue& operator[](const GenericValue& name) { - MemberIterator member = FindMember(name); - if (member != MemberEnd()) - return member->value; - else { - RAPIDJSON_ASSERT(false); // see above note - - // This will generate -Wexit-time-destructors in clang - // static GenericValue NullValue; - // return NullValue; - - // Use static buffer and placement-new to prevent destruction - static char buffer[sizeof(GenericValue)]; - return *new (buffer) GenericValue(); - } - } - template - const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } - -#if RAPIDJSON_HAS_STDSTRING - //! Get a value from an object associated with name (string object). - GenericValue& operator[](const std::basic_string& name) { return (*this)[GenericValue(StringRef(name))]; } - const GenericValue& operator[](const std::basic_string& name) const { return (*this)[GenericValue(StringRef(name))]; } -#endif - - //! Const member iterator - /*! \pre IsObject() == true */ - ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); } - //! Const \em past-the-end member iterator - /*! \pre IsObject() == true */ - ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); } - //! Member iterator - /*! \pre IsObject() == true */ - MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); } - //! \em Past-the-end member iterator - /*! \pre IsObject() == true */ - MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } - - //! Check whether a member exists in the object. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Whether a member with that name exists. - \note It is better to use FindMember() directly if you need the obtain the value as well. - \note Linear time complexity. - */ - bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } - -#if RAPIDJSON_HAS_STDSTRING - //! Check whether a member exists in the object with string object. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Whether a member with that name exists. - \note It is better to use FindMember() directly if you need the obtain the value as well. - \note Linear time complexity. - */ - bool HasMember(const std::basic_string& name) const { return FindMember(name) != MemberEnd(); } -#endif - - //! Check whether a member exists in the object with GenericValue name. - /*! - This version is faster because it does not need a StrLen(). It can also handle string with null character. - \param name Member name to be searched. - \pre IsObject() == true - \return Whether a member with that name exists. - \note It is better to use FindMember() directly if you need the obtain the value as well. - \note Linear time complexity. - */ - template - bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } - - //! Find member by name. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Iterator to member, if it exists. - Otherwise returns \ref MemberEnd(). - - \note Earlier versions of Rapidjson returned a \c NULL pointer, in case - the requested member doesn't exist. For consistency with e.g. - \c std::map, this has been changed to MemberEnd() now. - \note Linear time complexity. - */ - MemberIterator FindMember(const Ch* name) { - GenericValue n(StringRef(name)); - return FindMember(n); - } - - ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } - - //! Find member by name. - /*! - This version is faster because it does not need a StrLen(). It can also handle string with null character. - \param name Member name to be searched. - \pre IsObject() == true - \return Iterator to member, if it exists. - Otherwise returns \ref MemberEnd(). - - \note Earlier versions of Rapidjson returned a \c NULL pointer, in case - the requested member doesn't exist. For consistency with e.g. - \c std::map, this has been changed to MemberEnd() now. - \note Linear time complexity. - */ - template - MemberIterator FindMember(const GenericValue& name) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(name.IsString()); - MemberIterator member = MemberBegin(); - for ( ; member != MemberEnd(); ++member) - if (name.StringEqual(member->name)) - break; - return member; - } - template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } - -#if RAPIDJSON_HAS_STDSTRING - //! Find member by string object name. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Iterator to member, if it exists. - Otherwise returns \ref MemberEnd(). - */ - MemberIterator FindMember(const std::basic_string& name) { return FindMember(GenericValue(StringRef(name))); } - ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(GenericValue(StringRef(name))); } -#endif - - //! Add a member (name-value pair) to the object. - /*! \param name A string value as name of member. - \param value Value of any type. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note The ownership of \c name and \c value will be transferred to this object on success. - \pre IsObject() && name.IsString() - \post name.IsNull() && value.IsNull() - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(name.IsString()); - - ObjectData& o = data_.o; - if (o.size >= o.capacity) { - if (o.capacity == 0) { - o.capacity = kDefaultObjectCapacity; - SetMembersPointer(reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member)))); - } - else { - SizeType oldCapacity = o.capacity; - o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 - SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member)))); - } - } - Member* members = GetMembersPointer(); - members[o.size].name.RawAssign(name); - members[o.size].value.RawAssign(value); - o.size++; - return *this; - } - - //! Add a constant string value as member (name-value pair) to the object. - /*! \param name A string value as name of member. - \param value constant string reference as value of member. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) { - GenericValue v(value); - return AddMember(name, v, allocator); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Add a string object as member (name-value pair) to the object. - /*! \param name A string value as name of member. - \param value constant string reference as value of member. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { - GenericValue v(value, allocator); - return AddMember(name, v, allocator); - } -#endif - - //! Add any primitive value as member (name-value pair) to the object. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param name A string value as name of member. - \param value Value of primitive type \c T as value of member - \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref - AddMember(StringRefType, StringRefType, Allocator&). - All other pointer types would implicitly convert to \c bool, - use an explicit cast instead, if needed. - \note Amortized Constant time complexity. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) - AddMember(GenericValue& name, T value, Allocator& allocator) { - GenericValue v(value); - return AddMember(name, v, allocator); - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { - return AddMember(name, value, allocator); - } - GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { - return AddMember(name, value, allocator); - } - GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { - return AddMember(name, value, allocator); - } - GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { - GenericValue n(name); - return AddMember(n, value, allocator); - } -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - - - //! Add a member (name-value pair) to the object. - /*! \param name A constant string reference as name of member. - \param value Value of any type. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note The ownership of \c value will be transferred to this object on success. - \pre IsObject() - \post value.IsNull() - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { - GenericValue n(name); - return AddMember(n, value, allocator); - } - - //! Add a constant string value as member (name-value pair) to the object. - /*! \param name A constant string reference as name of member. - \param value constant string reference as value of member. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { - GenericValue v(value); - return AddMember(name, v, allocator); - } - - //! Add any primitive value as member (name-value pair) to the object. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param name A constant string reference as name of member. - \param value Value of primitive type \c T as value of member - \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref - AddMember(StringRefType, StringRefType, Allocator&). - All other pointer types would implicitly convert to \c bool, - use an explicit cast instead, if needed. - \note Amortized Constant time complexity. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) - AddMember(StringRefType name, T value, Allocator& allocator) { - GenericValue n(name); - return AddMember(n, value, allocator); - } - - //! Remove all members in the object. - /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. - \note Linear time complexity. - */ - void RemoveAllMembers() { - RAPIDJSON_ASSERT(IsObject()); - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - data_.o.size = 0; - } - - //! Remove a member in object by its name. - /*! \param name Name of member to be removed. - \return Whether the member existed. - \note This function may reorder the object members. Use \ref - EraseMember(ConstMemberIterator) if you need to preserve the - relative order of the remaining members. - \note Linear time complexity. - */ - bool RemoveMember(const Ch* name) { - GenericValue n(StringRef(name)); - return RemoveMember(n); - } - -#if RAPIDJSON_HAS_STDSTRING - bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); } -#endif - - template - bool RemoveMember(const GenericValue& name) { - MemberIterator m = FindMember(name); - if (m != MemberEnd()) { - RemoveMember(m); - return true; - } - else - return false; - } - - //! Remove a member in object by iterator. - /*! \param m member iterator (obtained by FindMember() or MemberBegin()). - \return the new iterator after removal. - \note This function may reorder the object members. Use \ref - EraseMember(ConstMemberIterator) if you need to preserve the - relative order of the remaining members. - \note Constant time complexity. - */ - MemberIterator RemoveMember(MemberIterator m) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(data_.o.size > 0); - RAPIDJSON_ASSERT(GetMembersPointer() != 0); - RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); - - MemberIterator last(GetMembersPointer() + (data_.o.size - 1)); - if (data_.o.size > 1 && m != last) - *m = *last; // Move the last one to this place - else - m->~Member(); // Only one left, just destroy - --data_.o.size; - return m; - } - - //! Remove a member from an object by iterator. - /*! \param pos iterator to the member to remove - \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() - \return Iterator following the removed element. - If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. - \note This function preserves the relative order of the remaining object - members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator). - \note Linear time complexity. - */ - MemberIterator EraseMember(ConstMemberIterator pos) { - return EraseMember(pos, pos +1); - } - - //! Remove members in the range [first, last) from an object. - /*! \param first iterator to the first member to remove - \param last iterator following the last member to remove - \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() - \return Iterator following the last removed element. - \note This function preserves the relative order of the remaining object - members. - \note Linear time complexity. - */ - MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(data_.o.size > 0); - RAPIDJSON_ASSERT(GetMembersPointer() != 0); - RAPIDJSON_ASSERT(first >= MemberBegin()); - RAPIDJSON_ASSERT(first <= last); - RAPIDJSON_ASSERT(last <= MemberEnd()); - - MemberIterator pos = MemberBegin() + (first - MemberBegin()); - for (MemberIterator itr = pos; itr != last; ++itr) - itr->~Member(); - std::memmove(&*pos, &*last, static_cast(MemberEnd() - last) * sizeof(Member)); - data_.o.size -= static_cast(last - first); - return pos; - } - - //! Erase a member in object by its name. - /*! \param name Name of member to be removed. - \return Whether the member existed. - \note Linear time complexity. - */ - bool EraseMember(const Ch* name) { - GenericValue n(StringRef(name)); - return EraseMember(n); - } - -#if RAPIDJSON_HAS_STDSTRING - bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); } -#endif - - template - bool EraseMember(const GenericValue& name) { - MemberIterator m = FindMember(name); - if (m != MemberEnd()) { - EraseMember(m); - return true; - } - else - return false; - } - - Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } - ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } - - //@} - - //!@name Array - //@{ - - //! Set this value as an empty array. - /*! \post IsArray == true */ - GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } - - //! Get the number of elements in array. - SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } - - //! Get the capacity of array. - SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } - - //! Check whether the array is empty. - bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } - - //! Remove all elements in the array. - /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. - \note Linear time complexity. - */ - void Clear() { - RAPIDJSON_ASSERT(IsArray()); - GenericValue* e = GetElementsPointer(); - for (GenericValue* v = e; v != e + data_.a.size; ++v) - v->~GenericValue(); - data_.a.size = 0; - } - - //! Get an element from array by index. - /*! \pre IsArray() == true - \param index Zero-based index of element. - \see operator[](T*) - */ - GenericValue& operator[](SizeType index) { - RAPIDJSON_ASSERT(IsArray()); - RAPIDJSON_ASSERT(index < data_.a.size); - return GetElementsPointer()[index]; - } - const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } - - //! Element iterator - /*! \pre IsArray() == true */ - ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); } - //! \em Past-the-end element iterator - /*! \pre IsArray() == true */ - ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; } - //! Constant element iterator - /*! \pre IsArray() == true */ - ConstValueIterator Begin() const { return const_cast(*this).Begin(); } - //! Constant \em past-the-end element iterator - /*! \pre IsArray() == true */ - ConstValueIterator End() const { return const_cast(*this).End(); } - - //! Request the array to have enough capacity to store elements. - /*! \param newCapacity The capacity that the array at least need to have. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note Linear time complexity. - */ - GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { - RAPIDJSON_ASSERT(IsArray()); - if (newCapacity > data_.a.capacity) { - SetElementsPointer(reinterpret_cast(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)))); - data_.a.capacity = newCapacity; - } - return *this; - } - - //! Append a GenericValue at the end of the array. - /*! \param value Value to be appended. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \post value.IsNull() == true - \return The value itself for fluent API. - \note The ownership of \c value will be transferred to this array on success. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - \note Amortized constant time complexity. - */ - GenericValue& PushBack(GenericValue& value, Allocator& allocator) { - RAPIDJSON_ASSERT(IsArray()); - if (data_.a.size >= data_.a.capacity) - Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); - GetElementsPointer()[data_.a.size++].RawAssign(value); - return *this; - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { - return PushBack(value, allocator); - } -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - - //! Append a constant string reference at the end of the array. - /*! \param value Constant string reference to be appended. - \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \return The value itself for fluent API. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - \note Amortized constant time complexity. - \see GenericStringRef - */ - GenericValue& PushBack(StringRefType value, Allocator& allocator) { - return (*this).template PushBack(value, allocator); - } - - //! Append a primitive value at the end of the array. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param value Value of primitive type T to be appended. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \return The value itself for fluent API. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref PushBack(GenericValue&, Allocator&) or \ref - PushBack(StringRefType, Allocator&). - All other pointer types would implicitly convert to \c bool, - use an explicit cast instead, if needed. - \note Amortized constant time complexity. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) - PushBack(T value, Allocator& allocator) { - GenericValue v(value); - return PushBack(v, allocator); - } - - //! Remove the last element in the array. - /*! - \note Constant time complexity. - */ - GenericValue& PopBack() { - RAPIDJSON_ASSERT(IsArray()); - RAPIDJSON_ASSERT(!Empty()); - GetElementsPointer()[--data_.a.size].~GenericValue(); - return *this; - } - - //! Remove an element of array by iterator. - /*! - \param pos iterator to the element to remove - \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() - \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. - \note Linear time complexity. - */ - ValueIterator Erase(ConstValueIterator pos) { - return Erase(pos, pos + 1); - } - - //! Remove elements in the range [first, last) of the array. - /*! - \param first iterator to the first element to remove - \param last iterator following the last element to remove - \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() - \return Iterator following the last removed element. - \note Linear time complexity. - */ - ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { - RAPIDJSON_ASSERT(IsArray()); - RAPIDJSON_ASSERT(data_.a.size > 0); - RAPIDJSON_ASSERT(GetElementsPointer() != 0); - RAPIDJSON_ASSERT(first >= Begin()); - RAPIDJSON_ASSERT(first <= last); - RAPIDJSON_ASSERT(last <= End()); - ValueIterator pos = Begin() + (first - Begin()); - for (ValueIterator itr = pos; itr != last; ++itr) - itr->~GenericValue(); - std::memmove(pos, last, static_cast(End() - last) * sizeof(GenericValue)); - data_.a.size -= static_cast(last - first); - return pos; - } - - Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); } - ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } - - //@} - - //!@name Number - //@{ - - int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; } - unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; } - int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; } - uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; } - - //! Get the value as double type. - /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless. - */ - double GetDouble() const { - RAPIDJSON_ASSERT(IsNumber()); - if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. - if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double - if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double - if ((data_.f.flags & kInt64Flag) != 0) return static_cast(data_.n.i64); // int64_t -> double (may lose precision) - RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast(data_.n.u64); // uint64_t -> double (may lose precision) - } - - //! Get the value as float type. - /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless. - */ - float GetFloat() const { - return static_cast(GetDouble()); - } - - GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } - GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } - GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } - GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } - GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } - GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(f); return *this; } - - //@} - - //!@name String - //@{ - - const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); } - - //! Get the length of string. - /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). - */ - SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } - - //! Set this value as a string without copying source string. - /*! This version has better performance with supplied length, and also support string containing null character. - \param s source string pointer. - \param length The length of source string, excluding the trailing null terminator. - \return The value itself for fluent API. - \post IsString() == true && GetString() == s && GetStringLength() == length - \see SetString(StringRefType) - */ - GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } - - //! Set this value as a string without copying source string. - /*! \param s source string reference - \return The value itself for fluent API. - \post IsString() == true && GetString() == s && GetStringLength() == s.length - */ - GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } - - //! Set this value as a string by copying from source string. - /*! This version has better performance with supplied length, and also support string containing null character. - \param s source string. - \param length The length of source string, excluding the trailing null terminator. - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length - */ - GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; } - - //! Set this value as a string by copying from source string. - /*! \param s source string. - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length - */ - GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); } - -#if RAPIDJSON_HAS_STDSTRING - //! Set this value as a string by copying from source string. - /*! \param s source string. - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() - \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. - */ - GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); } -#endif - - //@} - - //!@name Array - //@{ - - //! Templated version for checking whether this value is type T. - /*! - \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string - */ - template - bool Is() const { return internal::TypeHelper::Is(*this); } - - template - T Get() const { return internal::TypeHelper::Get(*this); } - - template - T Get() { return internal::TypeHelper::Get(*this); } - - template - ValueType& Set(const T& data) { return internal::TypeHelper::Set(*this, data); } - - template - ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper::Set(*this, data, allocator); } - - //@} - - //! Generate events of this value to a Handler. - /*! This function adopts the GoF visitor pattern. - Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. - It can also be used to deep clone this value via GenericDocument, which is also a Handler. - \tparam Handler type of handler. - \param handler An object implementing concept Handler. - */ - template - bool Accept(Handler& handler) const { - switch(GetType()) { - case kNullType: return handler.Null(); - case kFalseType: return handler.Bool(false); - case kTrueType: return handler.Bool(true); - - case kObjectType: - if (RAPIDJSON_UNLIKELY(!handler.StartObject())) - return false; - for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { - RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. - if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0))) - return false; - if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) - return false; - } - return handler.EndObject(data_.o.size); - - case kArrayType: - if (RAPIDJSON_UNLIKELY(!handler.StartArray())) - return false; - for (const GenericValue* v = Begin(); v != End(); ++v) - if (RAPIDJSON_UNLIKELY(!v->Accept(handler))) - return false; - return handler.EndArray(data_.a.size); - - case kStringType: - return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); - - default: - RAPIDJSON_ASSERT(GetType() == kNumberType); - if (IsDouble()) return handler.Double(data_.n.d); - else if (IsInt()) return handler.Int(data_.n.i.i); - else if (IsUint()) return handler.Uint(data_.n.u.u); - else if (IsInt64()) return handler.Int64(data_.n.i64); - else return handler.Uint64(data_.n.u64); - } - } - -private: - template friend class GenericValue; - template friend class GenericDocument; - - enum { - kBoolFlag = 0x0008, - kNumberFlag = 0x0010, - kIntFlag = 0x0020, - kUintFlag = 0x0040, - kInt64Flag = 0x0080, - kUint64Flag = 0x0100, - kDoubleFlag = 0x0200, - kStringFlag = 0x0400, - kCopyFlag = 0x0800, - kInlineStrFlag = 0x1000, - - // Initial flags of different types. - kNullFlag = kNullType, - kTrueFlag = kTrueType | kBoolFlag, - kFalseFlag = kFalseType | kBoolFlag, - kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, - kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, - kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, - kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, - kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, - kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag, - kConstStringFlag = kStringType | kStringFlag, - kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, - kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag, - kObjectFlag = kObjectType, - kArrayFlag = kArrayType, - - kTypeMask = 0x07 - }; - - static const SizeType kDefaultArrayCapacity = 16; - static const SizeType kDefaultObjectCapacity = 16; - - struct Flag { -#if RAPIDJSON_48BITPOINTER_OPTIMIZATION - char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer -#elif RAPIDJSON_64BIT - char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes -#else - char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes -#endif - uint16_t flags; - }; - - struct String { - SizeType length; - SizeType hashcode; //!< reserved - const Ch* str; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - - // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars - // (excluding the terminating zero) and store a value to determine the length of the contained - // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string - // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as - // the string terminator as well. For getting the string length back from that value just use - // "MaxSize - str[LenPos]". - // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode, - // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings). - struct ShortString { - enum { MaxChars = sizeof(static_cast(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; - Ch str[MaxChars]; - - inline static bool Usable(SizeType len) { return (MaxSize >= len); } - inline void SetLength(SizeType len) { str[LenPos] = static_cast(MaxSize - len); } - inline SizeType GetLength() const { return static_cast(MaxSize - str[LenPos]); } - }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - - // By using proper binary layout, retrieval of different integer types do not need conversions. - union Number { -#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN - struct I { - int i; - char padding[4]; - }i; - struct U { - unsigned u; - char padding2[4]; - }u; -#else - struct I { - char padding[4]; - int i; - }i; - struct U { - char padding2[4]; - unsigned u; - }u; -#endif - int64_t i64; - uint64_t u64; - double d; - }; // 8 bytes - - struct ObjectData { - SizeType size; - SizeType capacity; - Member* members; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - - struct ArrayData { - SizeType size; - SizeType capacity; - GenericValue* elements; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - - union Data { - String s; - ShortString ss; - Number n; - ObjectData o; - ArrayData a; - Flag f; - }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION - - RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); } - RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } - RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } - RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); } - RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); } - RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } - - // Initialize this value as array with initial data, without calling destructor. - void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { - data_.f.flags = kArrayFlag; - if (count) { - GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); - SetElementsPointer(e); - std::memcpy(e, values, count * sizeof(GenericValue)); - } - else - SetElementsPointer(0); - data_.a.size = data_.a.capacity = count; - } - - //! Initialize this value as object with initial data, without calling destructor. - void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { - data_.f.flags = kObjectFlag; - if (count) { - Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); - SetMembersPointer(m); - std::memcpy(m, members, count * sizeof(Member)); - } - else - SetMembersPointer(0); - data_.o.size = data_.o.capacity = count; - } - - //! Initialize this value as constant string, without calling destructor. - void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { - data_.f.flags = kConstStringFlag; - SetStringPointer(s); - data_.s.length = s.length; - } - - //! Initialize this value as copy string with initial data, without calling destructor. - void SetStringRaw(StringRefType s, Allocator& allocator) { - Ch* str = 0; - if (ShortString::Usable(s.length)) { - data_.f.flags = kShortStringFlag; - data_.ss.SetLength(s.length); - str = data_.ss.str; - } else { - data_.f.flags = kCopyStringFlag; - data_.s.length = s.length; - str = static_cast(allocator.Malloc((s.length + 1) * sizeof(Ch))); - SetStringPointer(str); - } - std::memcpy(str, s, s.length * sizeof(Ch)); - str[s.length] = '\0'; - } - - //! Assignment without calling destructor - void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { - data_ = rhs.data_; - // data_.f.flags = rhs.data_.f.flags; - rhs.data_.f.flags = kNullFlag; - } - - template - bool StringEqual(const GenericValue& rhs) const { - RAPIDJSON_ASSERT(IsString()); - RAPIDJSON_ASSERT(rhs.IsString()); - - const SizeType len1 = GetStringLength(); - const SizeType len2 = rhs.GetStringLength(); - if(len1 != len2) { return false; } - - const Ch* const str1 = GetString(); - const Ch* const str2 = rhs.GetString(); - if(str1 == str2) { return true; } // fast path for constant string - - return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); - } - - Data data_; -}; - -//! GenericValue with UTF8 encoding -typedef GenericValue > Value; - -/////////////////////////////////////////////////////////////////////////////// -// GenericDocument - -//! A document for parsing JSON text as DOM. -/*! - \note implements Handler concept - \tparam Encoding Encoding for both parsing and string storage. - \tparam Allocator Allocator for allocating memory for the DOM - \tparam StackAllocator Allocator for allocating memory for stack during parsing. - \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. -*/ -template , typename StackAllocator = CrtAllocator> -class GenericDocument : public GenericValue { -public: - typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. - typedef GenericValue ValueType; //!< Value type of the document. - typedef Allocator AllocatorType; //!< Allocator type from template parameter. - - //! Constructor - /*! Creates an empty document of specified type. - \param type Mandatory type of object to create. - \param allocator Optional allocator for allocating memory. - \param stackCapacity Optional initial capacity of stack in bytes. - \param stackAllocator Optional allocator for allocating memory for stack. - */ - explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : - GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() - { - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); - } - - //! Constructor - /*! Creates an empty document which type is Null. - \param allocator Optional allocator for allocating memory. - \param stackCapacity Optional initial capacity of stack in bytes. - \param stackAllocator Optional allocator for allocating memory for stack. - */ - GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : - allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() - { - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move constructor in C++11 - GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT - : ValueType(std::forward(rhs)), // explicit cast to avoid prohibited move from Document - allocator_(rhs.allocator_), - ownAllocator_(rhs.ownAllocator_), - stack_(std::move(rhs.stack_)), - parseResult_(rhs.parseResult_) - { - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.parseResult_ = ParseResult(); - } -#endif - - ~GenericDocument() { - Destroy(); - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move assignment in C++11 - GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT - { - // The cast to ValueType is necessary here, because otherwise it would - // attempt to call GenericValue's templated assignment operator. - ValueType::operator=(std::forward(rhs)); - - // Calling the destructor here would prematurely call stack_'s destructor - Destroy(); - - allocator_ = rhs.allocator_; - ownAllocator_ = rhs.ownAllocator_; - stack_ = std::move(rhs.stack_); - parseResult_ = rhs.parseResult_; - - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.parseResult_ = ParseResult(); - - return *this; - } -#endif - - //! Exchange the contents of this document with those of another. - /*! - \param rhs Another document. - \note Constant complexity. - \see GenericValue::Swap - */ - GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { - ValueType::Swap(rhs); - stack_.Swap(rhs.stack_); - internal::Swap(allocator_, rhs.allocator_); - internal::Swap(ownAllocator_, rhs.ownAllocator_); - internal::Swap(parseResult_, rhs.parseResult_); - return *this; - } - - //! free-standing swap function helper - /*! - Helper function to enable support for common swap implementation pattern based on \c std::swap: - \code - void swap(MyClass& a, MyClass& b) { - using std::swap; - swap(a.doc, b.doc); - // ... - } - \endcode - \see Swap() - */ - friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } - - //! Populate this document by a generator which produces SAX events. - /*! \tparam Generator A functor with bool f(Handler) prototype. - \param g Generator functor which sends SAX events to the parameter. - \return The document itself for fluent API. - */ - template - GenericDocument& Populate(Generator& g) { - ClearStackOnExit scope(*this); - if (g(*this)) { - RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object - ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document - } - return *this; - } - - //!@name Parse from stream - //!@{ - - //! Parse JSON text from an input stream (with Encoding conversion) - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam SourceEncoding Encoding of input stream - \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - GenericReader reader( - stack_.HasAllocator() ? &stack_.GetAllocator() : 0); - ClearStackOnExit scope(*this); - parseResult_ = reader.template Parse(is, *this); - if (parseResult_) { - RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object - ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document - } - return *this; - } - - //! Parse JSON text from an input stream - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - return ParseStream(is); - } - - //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) - /*! \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - return ParseStream(is); - } - //!@} - - //!@name Parse in-place from mutable string - //!@{ - - //! Parse JSON text from a mutable string - /*! \tparam parseFlags Combination of \ref ParseFlag. - \param str Mutable zero-terminated string to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseInsitu(Ch* str) { - GenericInsituStringStream s(str); - return ParseStream(s); - } - - //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) - /*! \param str Mutable zero-terminated string to be parsed. - \return The document itself for fluent API. - */ - GenericDocument& ParseInsitu(Ch* str) { - return ParseInsitu(str); - } - //!@} - - //!@name Parse from read-only string - //!@{ - - //! Parse JSON text from a read-only string (with Encoding conversion) - /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). - \tparam SourceEncoding Transcoding from input Encoding - \param str Read-only zero-terminated string to be parsed. - */ - template - GenericDocument& Parse(const typename SourceEncoding::Ch* str) { - RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); - GenericStringStream s(str); - return ParseStream(s); - } - - //! Parse JSON text from a read-only string - /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). - \param str Read-only zero-terminated string to be parsed. - */ - template - GenericDocument& Parse(const Ch* str) { - return Parse(str); - } - - //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) - /*! \param str Read-only zero-terminated string to be parsed. - */ - GenericDocument& Parse(const Ch* str) { - return Parse(str); - } - - template - GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { - RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); - MemoryStream ms(static_cast(str), length * sizeof(typename SourceEncoding::Ch)); - EncodedInputStream is(ms); - ParseStream(is); - return *this; - } - - template - GenericDocument& Parse(const Ch* str, size_t length) { - return Parse(str, length); - } - - GenericDocument& Parse(const Ch* str, size_t length) { - return Parse(str, length); - } - -#if RAPIDJSON_HAS_STDSTRING - template - GenericDocument& Parse(const std::basic_string& str) { - // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t) - return Parse(str.c_str()); - } - - template - GenericDocument& Parse(const std::basic_string& str) { - return Parse(str.c_str()); - } - - GenericDocument& Parse(const std::basic_string& str) { - return Parse(str); - } -#endif // RAPIDJSON_HAS_STDSTRING - - //!@} - - //!@name Handling parse errors - //!@{ - - //! Whether a parse error has occured in the last parsing. - bool HasParseError() const { return parseResult_.IsError(); } - - //! Get the \ref ParseErrorCode of last parsing. - ParseErrorCode GetParseError() const { return parseResult_.Code(); } - - //! Get the position of last parsing error in input, 0 otherwise. - size_t GetErrorOffset() const { return parseResult_.Offset(); } - - //! Implicit conversion to get the last parse result -#ifndef __clang // -Wdocumentation - /*! \return \ref ParseResult of the last parse operation - - \code - Document doc; - ParseResult ok = doc.Parse(json); - if (!ok) - printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset()); - \endcode - */ -#endif - operator ParseResult() const { return parseResult_; } - //!@} - - //! Get the allocator of this document. - Allocator& GetAllocator() { - RAPIDJSON_ASSERT(allocator_); - return *allocator_; - } - - //! Get the capacity of stack in bytes. - size_t GetStackCapacity() const { return stack_.GetCapacity(); } - -private: - // clear stack on any exit from ParseStream, e.g. due to exception - struct ClearStackOnExit { - explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} - ~ClearStackOnExit() { d_.ClearStack(); } - private: - ClearStackOnExit(const ClearStackOnExit&); - ClearStackOnExit& operator=(const ClearStackOnExit&); - GenericDocument& d_; - }; - - // callers of the following private Handler functions - // template friend class GenericReader; // for parsing - template friend class GenericValue; // for deep copying - -public: - // Implementation of Handler - bool Null() { new (stack_.template Push()) ValueType(); return true; } - bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } - bool Int(int i) { new (stack_.template Push()) ValueType(i); return true; } - bool Uint(unsigned i) { new (stack_.template Push()) ValueType(i); return true; } - bool Int64(int64_t i) { new (stack_.template Push()) ValueType(i); return true; } - bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } - bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } - - bool RawNumber(const Ch* str, SizeType length, bool copy) { - if (copy) - new (stack_.template Push()) ValueType(str, length, GetAllocator()); - else - new (stack_.template Push()) ValueType(str, length); - return true; - } - - bool String(const Ch* str, SizeType length, bool copy) { - if (copy) - new (stack_.template Push()) ValueType(str, length, GetAllocator()); - else - new (stack_.template Push()) ValueType(str, length); - return true; - } - - bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } - - bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } - - bool EndObject(SizeType memberCount) { - typename ValueType::Member* members = stack_.template Pop(memberCount); - stack_.template Top()->SetObjectRaw(members, memberCount, GetAllocator()); - return true; - } - - bool StartArray() { new (stack_.template Push()) ValueType(kArrayType); return true; } - - bool EndArray(SizeType elementCount) { - ValueType* elements = stack_.template Pop(elementCount); - stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); - return true; - } - -private: - //! Prohibit copying - GenericDocument(const GenericDocument&); - //! Prohibit assignment - GenericDocument& operator=(const GenericDocument&); - - void ClearStack() { - if (Allocator::kNeedFree) - while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) - (stack_.template Pop(1))->~ValueType(); - else - stack_.Clear(); - stack_.ShrinkToFit(); - } - - void Destroy() { - RAPIDJSON_DELETE(ownAllocator_); - } - - static const size_t kDefaultStackCapacity = 1024; - Allocator* allocator_; - Allocator* ownAllocator_; - internal::Stack stack_; - ParseResult parseResult_; -}; - -//! GenericDocument with UTF8 encoding -typedef GenericDocument > Document; - -// defined here due to the dependency on GenericDocument -template -template -inline -GenericValue::GenericValue(const GenericValue& rhs, Allocator& allocator) -{ - switch (rhs.GetType()) { - case kObjectType: - case kArrayType: { // perform deep copy via SAX Handler - GenericDocument d(&allocator); - rhs.Accept(d); - RawAssign(*d.stack_.template Pop(1)); - } - break; - case kStringType: - if (rhs.data_.f.flags == kConstStringFlag) { - data_.f.flags = rhs.data_.f.flags; - data_ = *reinterpret_cast(&rhs.data_); - } else { - SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); - } - break; - default: - data_.f.flags = rhs.data_.f.flags; - data_ = *reinterpret_cast(&rhs.data_); - break; - } -} - -//! Helper class for accessing Value of array type. -/*! - Instance of this helper class is obtained by \c GenericValue::GetArray(). - In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. -*/ -template -class GenericArray { -public: - typedef GenericArray ConstArray; - typedef GenericArray Array; - typedef ValueT PlainType; - typedef typename internal::MaybeAddConst::Type ValueType; - typedef ValueType* ValueIterator; // This may be const or non-const iterator - typedef const ValueT* ConstValueIterator; - typedef typename ValueType::AllocatorType AllocatorType; - typedef typename ValueType::StringRefType StringRefType; - - template - friend class GenericValue; - - GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} - GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } - ~GenericArray() {} - - SizeType Size() const { return value_.Size(); } - SizeType Capacity() const { return value_.Capacity(); } - bool Empty() const { return value_.Empty(); } - void Clear() const { value_.Clear(); } - ValueType& operator[](SizeType index) const { return value_[index]; } - ValueIterator Begin() const { return value_.Begin(); } - ValueIterator End() const { return value_.End(); } - GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; } - GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } - GenericArray PopBack() const { value_.PopBack(); return *this; } - ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); } - ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); } - -#if RAPIDJSON_HAS_CXX11_RANGE_FOR - ValueIterator begin() const { return value_.Begin(); } - ValueIterator end() const { return value_.End(); } -#endif - -private: - GenericArray(); - GenericArray(ValueType& value) : value_(value) {} - ValueType& value_; -}; - -//! Helper class for accessing Value of object type. -/*! - Instance of this helper class is obtained by \c GenericValue::GetObject(). - In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. -*/ -template -class GenericObject { -public: - typedef GenericObject ConstObject; - typedef GenericObject Object; - typedef ValueT PlainType; - typedef typename internal::MaybeAddConst::Type ValueType; - typedef GenericMemberIterator MemberIterator; // This may be const or non-const iterator - typedef GenericMemberIterator ConstMemberIterator; - typedef typename ValueType::AllocatorType AllocatorType; - typedef typename ValueType::StringRefType StringRefType; - typedef typename ValueType::EncodingType EncodingType; - typedef typename ValueType::Ch Ch; - - template - friend class GenericValue; - - GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} - GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } - ~GenericObject() {} - - SizeType MemberCount() const { return value_.MemberCount(); } - bool ObjectEmpty() const { return value_.ObjectEmpty(); } - template ValueType& operator[](T* name) const { return value_[name]; } - template ValueType& operator[](const GenericValue& name) const { return value_[name]; } -#if RAPIDJSON_HAS_STDSTRING - ValueType& operator[](const std::basic_string& name) const { return value_[name]; } -#endif - MemberIterator MemberBegin() const { return value_.MemberBegin(); } - MemberIterator MemberEnd() const { return value_.MemberEnd(); } - bool HasMember(const Ch* name) const { return value_.HasMember(name); } -#if RAPIDJSON_HAS_STDSTRING - bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } -#endif - template bool HasMember(const GenericValue& name) const { return value_.HasMember(name); } - MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); } - template MemberIterator FindMember(const GenericValue& name) const { return value_.FindMember(name); } -#if RAPIDJSON_HAS_STDSTRING - MemberIterator FindMember(const std::basic_string& name) const { return value_.FindMember(name); } -#endif - GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } -#if RAPIDJSON_HAS_STDSTRING - GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } -#endif - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - void RemoveAllMembers() { return value_.RemoveAllMembers(); } - bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } -#if RAPIDJSON_HAS_STDSTRING - bool RemoveMember(const std::basic_string& name) const { return value_.RemoveMember(name); } -#endif - template bool RemoveMember(const GenericValue& name) const { return value_.RemoveMember(name); } - MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); } - MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); } - MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); } - bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } -#if RAPIDJSON_HAS_STDSTRING - bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } -#endif - template bool EraseMember(const GenericValue& name) const { return value_.EraseMember(name); } - -#if RAPIDJSON_HAS_CXX11_RANGE_FOR - MemberIterator begin() const { return value_.MemberBegin(); } - MemberIterator end() const { return value_.MemberEnd(); } -#endif - -private: - GenericObject(); - GenericObject(ValueType& value) : value_(value) {} - ValueType& value_; -}; - -RAPIDJSON_NAMESPACE_END -RAPIDJSON_DIAG_POP - -#endif // RAPIDJSON_DOCUMENT_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/encodedstream.h b/src/Native/libcryptonight/3rdparty/rapidjson/encodedstream.h deleted file mode 100644 index 145068386..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/encodedstream.h +++ /dev/null @@ -1,299 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ENCODEDSTREAM_H_ -#define RAPIDJSON_ENCODEDSTREAM_H_ - -#include "stream.h" -#include "memorystream.h" - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Input byte stream wrapper with a statically bound encoding. -/*! - \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. - \tparam InputByteStream Type of input byte stream. For example, FileReadStream. -*/ -template -class EncodedInputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); -public: - typedef typename Encoding::Ch Ch; - - EncodedInputStream(InputByteStream& is) : is_(is) { - current_ = Encoding::TakeBOM(is_); - } - - Ch Peek() const { return current_; } - Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } - size_t Tell() const { return is_.Tell(); } - - // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - EncodedInputStream(const EncodedInputStream&); - EncodedInputStream& operator=(const EncodedInputStream&); - - InputByteStream& is_; - Ch current_; -}; - -//! Specialized for UTF8 MemoryStream. -template <> -class EncodedInputStream, MemoryStream> { -public: - typedef UTF8<>::Ch Ch; - - EncodedInputStream(MemoryStream& is) : is_(is) { - if (static_cast(is_.Peek()) == 0xEFu) is_.Take(); - if (static_cast(is_.Peek()) == 0xBBu) is_.Take(); - if (static_cast(is_.Peek()) == 0xBFu) is_.Take(); - } - Ch Peek() const { return is_.Peek(); } - Ch Take() { return is_.Take(); } - size_t Tell() const { return is_.Tell(); } - - // Not implemented - void Put(Ch) {} - void Flush() {} - Ch* PutBegin() { return 0; } - size_t PutEnd(Ch*) { return 0; } - - MemoryStream& is_; - -private: - EncodedInputStream(const EncodedInputStream&); - EncodedInputStream& operator=(const EncodedInputStream&); -}; - -//! Output byte stream wrapper with statically bound encoding. -/*! - \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. - \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream. -*/ -template -class EncodedOutputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); -public: - typedef typename Encoding::Ch Ch; - - EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { - if (putBOM) - Encoding::PutBOM(os_); - } - - void Put(Ch c) { Encoding::Put(os_, c); } - void Flush() { os_.Flush(); } - - // Not implemented - Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} - Ch Take() { RAPIDJSON_ASSERT(false); return 0;} - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - EncodedOutputStream(const EncodedOutputStream&); - EncodedOutputStream& operator=(const EncodedOutputStream&); - - OutputByteStream& os_; -}; - -#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x - -//! Input stream wrapper with dynamically bound encoding and automatic encoding detection. -/*! - \tparam CharType Type of character for reading. - \tparam InputByteStream type of input byte stream to be wrapped. -*/ -template -class AutoUTFInputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); -public: - typedef CharType Ch; - - //! Constructor. - /*! - \param is input stream to be wrapped. - \param type UTF encoding type if it is not detected from the stream. - */ - AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { - RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); - DetectType(); - static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; - takeFunc_ = f[type_]; - current_ = takeFunc_(*is_); - } - - UTFType GetType() const { return type_; } - bool HasBOM() const { return hasBOM_; } - - Ch Peek() const { return current_; } - Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } - size_t Tell() const { return is_->Tell(); } - - // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - AutoUTFInputStream(const AutoUTFInputStream&); - AutoUTFInputStream& operator=(const AutoUTFInputStream&); - - // Detect encoding type with BOM or RFC 4627 - void DetectType() { - // BOM (Byte Order Mark): - // 00 00 FE FF UTF-32BE - // FF FE 00 00 UTF-32LE - // FE FF UTF-16BE - // FF FE UTF-16LE - // EF BB BF UTF-8 - - const unsigned char* c = reinterpret_cast(is_->Peek4()); - if (!c) - return; - - unsigned bom = static_cast(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); - hasBOM_ = false; - if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } - else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } - else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } - else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } - else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } - - // RFC 4627: Section 3 - // "Since the first two characters of a JSON text will always be ASCII - // characters [RFC0020], it is possible to determine whether an octet - // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking - // at the pattern of nulls in the first four octets." - // 00 00 00 xx UTF-32BE - // 00 xx 00 xx UTF-16BE - // xx 00 00 00 UTF-32LE - // xx 00 xx 00 UTF-16LE - // xx xx xx xx UTF-8 - - if (!hasBOM_) { - unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); - switch (pattern) { - case 0x08: type_ = kUTF32BE; break; - case 0x0A: type_ = kUTF16BE; break; - case 0x01: type_ = kUTF32LE; break; - case 0x05: type_ = kUTF16LE; break; - case 0x0F: type_ = kUTF8; break; - default: break; // Use type defined by user. - } - } - - // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. - if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); - if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); - } - - typedef Ch (*TakeFunc)(InputByteStream& is); - InputByteStream* is_; - UTFType type_; - Ch current_; - TakeFunc takeFunc_; - bool hasBOM_; -}; - -//! Output stream wrapper with dynamically bound encoding and automatic encoding detection. -/*! - \tparam CharType Type of character for writing. - \tparam OutputByteStream type of output byte stream to be wrapped. -*/ -template -class AutoUTFOutputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); -public: - typedef CharType Ch; - - //! Constructor. - /*! - \param os output stream to be wrapped. - \param type UTF encoding type. - \param putBOM Whether to write BOM at the beginning of the stream. - */ - AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { - RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); - - // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. - if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); - if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); - - static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; - putFunc_ = f[type_]; - - if (putBOM) - PutBOM(); - } - - UTFType GetType() const { return type_; } - - void Put(Ch c) { putFunc_(*os_, c); } - void Flush() { os_->Flush(); } - - // Not implemented - Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} - Ch Take() { RAPIDJSON_ASSERT(false); return 0;} - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - AutoUTFOutputStream(const AutoUTFOutputStream&); - AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); - - void PutBOM() { - typedef void (*PutBOMFunc)(OutputByteStream&); - static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; - f[type_](*os_); - } - - typedef void (*PutFunc)(OutputByteStream&, Ch); - - OutputByteStream* os_; - UTFType type_; - PutFunc putFunc_; -}; - -#undef RAPIDJSON_ENCODINGS_FUNC - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/encodings.h b/src/Native/libcryptonight/3rdparty/rapidjson/encodings.h deleted file mode 100644 index baa7c2b17..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/encodings.h +++ /dev/null @@ -1,716 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ENCODINGS_H_ -#define RAPIDJSON_ENCODINGS_H_ - -#include "rapidjson.h" - -#ifdef _MSC_VER -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data -RAPIDJSON_DIAG_OFF(4702) // unreachable code -#elif defined(__GNUC__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -RAPIDJSON_DIAG_OFF(overflow) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// Encoding - -/*! \class rapidjson::Encoding - \brief Concept for encoding of Unicode characters. - -\code -concept Encoding { - typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. - - enum { supportUnicode = 1 }; // or 0 if not supporting unicode - - //! \brief Encode a Unicode codepoint to an output stream. - //! \param os Output stream. - //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. - template - static void Encode(OutputStream& os, unsigned codepoint); - - //! \brief Decode a Unicode codepoint from an input stream. - //! \param is Input stream. - //! \param codepoint Output of the unicode codepoint. - //! \return true if a valid codepoint can be decoded from the stream. - template - static bool Decode(InputStream& is, unsigned* codepoint); - - //! \brief Validate one Unicode codepoint from an encoded stream. - //! \param is Input stream to obtain codepoint. - //! \param os Output for copying one codepoint. - //! \return true if it is valid. - //! \note This function just validating and copying the codepoint without actually decode it. - template - static bool Validate(InputStream& is, OutputStream& os); - - // The following functions are deal with byte streams. - - //! Take a character from input byte stream, skip BOM if exist. - template - static CharType TakeBOM(InputByteStream& is); - - //! Take a character from input byte stream. - template - static Ch Take(InputByteStream& is); - - //! Put BOM to output byte stream. - template - static void PutBOM(OutputByteStream& os); - - //! Put a character to output byte stream. - template - static void Put(OutputByteStream& os, Ch c); -}; -\endcode -*/ - -/////////////////////////////////////////////////////////////////////////////// -// UTF8 - -//! UTF-8 encoding. -/*! http://en.wikipedia.org/wiki/UTF-8 - http://tools.ietf.org/html/rfc3629 - \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. - \note implements Encoding concept -*/ -template -struct UTF8 { - typedef CharType Ch; - - enum { supportUnicode = 1 }; - - template - static void Encode(OutputStream& os, unsigned codepoint) { - if (codepoint <= 0x7F) - os.Put(static_cast(codepoint & 0xFF)); - else if (codepoint <= 0x7FF) { - os.Put(static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); - os.Put(static_cast(0x80 | ((codepoint & 0x3F)))); - } - else if (codepoint <= 0xFFFF) { - os.Put(static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); - os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - os.Put(static_cast(0x80 | (codepoint & 0x3F))); - } - else { - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - os.Put(static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); - os.Put(static_cast(0x80 | ((codepoint >> 12) & 0x3F))); - os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - os.Put(static_cast(0x80 | (codepoint & 0x3F))); - } - } - - template - static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - if (codepoint <= 0x7F) - PutUnsafe(os, static_cast(codepoint & 0xFF)); - else if (codepoint <= 0x7FF) { - PutUnsafe(os, static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); - PutUnsafe(os, static_cast(0x80 | ((codepoint & 0x3F)))); - } - else if (codepoint <= 0xFFFF) { - PutUnsafe(os, static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); - PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); - } - else { - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - PutUnsafe(os, static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); - PutUnsafe(os, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); - PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); - } - } - - template - static bool Decode(InputStream& is, unsigned* codepoint) { -#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) -#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) -#define TAIL() COPY(); TRANS(0x70) - typename InputStream::Ch c = is.Take(); - if (!(c & 0x80)) { - *codepoint = static_cast(c); - return true; - } - - unsigned char type = GetRange(static_cast(c)); - if (type >= 32) { - *codepoint = 0; - } else { - *codepoint = (0xFF >> type) & static_cast(c); - } - bool result = true; - switch (type) { - case 2: TAIL(); return result; - case 3: TAIL(); TAIL(); return result; - case 4: COPY(); TRANS(0x50); TAIL(); return result; - case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; - case 6: TAIL(); TAIL(); TAIL(); return result; - case 10: COPY(); TRANS(0x20); TAIL(); return result; - case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; - default: return false; - } -#undef COPY -#undef TRANS -#undef TAIL - } - - template - static bool Validate(InputStream& is, OutputStream& os) { -#define COPY() os.Put(c = is.Take()) -#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) -#define TAIL() COPY(); TRANS(0x70) - Ch c; - COPY(); - if (!(c & 0x80)) - return true; - - bool result = true; - switch (GetRange(static_cast(c))) { - case 2: TAIL(); return result; - case 3: TAIL(); TAIL(); return result; - case 4: COPY(); TRANS(0x50); TAIL(); return result; - case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; - case 6: TAIL(); TAIL(); TAIL(); return result; - case 10: COPY(); TRANS(0x20); TAIL(); return result; - case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; - default: return false; - } -#undef COPY -#undef TRANS -#undef TAIL - } - - static unsigned char GetRange(unsigned char c) { - // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ - // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. - static const unsigned char type[] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, - 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, - }; - return type[c]; - } - - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - typename InputByteStream::Ch c = Take(is); - if (static_cast(c) != 0xEFu) return c; - c = is.Take(); - if (static_cast(c) != 0xBBu) return c; - c = is.Take(); - if (static_cast(c) != 0xBFu) return c; - c = is.Take(); - return c; - } - - template - static Ch Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - return static_cast(is.Take()); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0xEFu)); - os.Put(static_cast(0xBBu)); - os.Put(static_cast(0xBFu)); - } - - template - static void Put(OutputByteStream& os, Ch c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(c)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// UTF16 - -//! UTF-16 encoding. -/*! http://en.wikipedia.org/wiki/UTF-16 - http://tools.ietf.org/html/rfc2781 - \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. - \note implements Encoding concept - - \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. - For streaming, use UTF16LE and UTF16BE, which handle endianness. -*/ -template -struct UTF16 { - typedef CharType Ch; - RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); - - enum { supportUnicode = 1 }; - - template - static void Encode(OutputStream& os, unsigned codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); - if (codepoint <= 0xFFFF) { - RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair - os.Put(static_cast(codepoint)); - } - else { - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - unsigned v = codepoint - 0x10000; - os.Put(static_cast((v >> 10) | 0xD800)); - os.Put((v & 0x3FF) | 0xDC00); - } - } - - - template - static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); - if (codepoint <= 0xFFFF) { - RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair - PutUnsafe(os, static_cast(codepoint)); - } - else { - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - unsigned v = codepoint - 0x10000; - PutUnsafe(os, static_cast((v >> 10) | 0xD800)); - PutUnsafe(os, (v & 0x3FF) | 0xDC00); - } - } - - template - static bool Decode(InputStream& is, unsigned* codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); - typename InputStream::Ch c = is.Take(); - if (c < 0xD800 || c > 0xDFFF) { - *codepoint = static_cast(c); - return true; - } - else if (c <= 0xDBFF) { - *codepoint = (static_cast(c) & 0x3FF) << 10; - c = is.Take(); - *codepoint |= (static_cast(c) & 0x3FF); - *codepoint += 0x10000; - return c >= 0xDC00 && c <= 0xDFFF; - } - return false; - } - - template - static bool Validate(InputStream& is, OutputStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); - typename InputStream::Ch c; - os.Put(static_cast(c = is.Take())); - if (c < 0xD800 || c > 0xDFFF) - return true; - else if (c <= 0xDBFF) { - os.Put(c = is.Take()); - return c >= 0xDC00 && c <= 0xDFFF; - } - return false; - } -}; - -//! UTF-16 little endian encoding. -template -struct UTF16LE : UTF16 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return static_cast(c) == 0xFEFFu ? Take(is) : c; - } - - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - unsigned c = static_cast(is.Take()); - c |= static_cast(static_cast(is.Take())) << 8; - return static_cast(c); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0xFFu)); - os.Put(static_cast(0xFEu)); - } - - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(static_cast(c) & 0xFFu)); - os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); - } -}; - -//! UTF-16 big endian encoding. -template -struct UTF16BE : UTF16 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return static_cast(c) == 0xFEFFu ? Take(is) : c; - } - - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - unsigned c = static_cast(static_cast(is.Take())) << 8; - c |= static_cast(is.Take()); - return static_cast(c); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0xFEu)); - os.Put(static_cast(0xFFu)); - } - - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); - os.Put(static_cast(static_cast(c) & 0xFFu)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// UTF32 - -//! UTF-32 encoding. -/*! http://en.wikipedia.org/wiki/UTF-32 - \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. - \note implements Encoding concept - - \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. - For streaming, use UTF32LE and UTF32BE, which handle endianness. -*/ -template -struct UTF32 { - typedef CharType Ch; - RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); - - enum { supportUnicode = 1 }; - - template - static void Encode(OutputStream& os, unsigned codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - os.Put(codepoint); - } - - template - static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - PutUnsafe(os, codepoint); - } - - template - static bool Decode(InputStream& is, unsigned* codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); - Ch c = is.Take(); - *codepoint = c; - return c <= 0x10FFFF; - } - - template - static bool Validate(InputStream& is, OutputStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); - Ch c; - os.Put(c = is.Take()); - return c <= 0x10FFFF; - } -}; - -//! UTF-32 little endian enocoding. -template -struct UTF32LE : UTF32 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return static_cast(c) == 0x0000FEFFu ? Take(is) : c; - } - - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - unsigned c = static_cast(is.Take()); - c |= static_cast(static_cast(is.Take())) << 8; - c |= static_cast(static_cast(is.Take())) << 16; - c |= static_cast(static_cast(is.Take())) << 24; - return static_cast(c); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0xFFu)); - os.Put(static_cast(0xFEu)); - os.Put(static_cast(0x00u)); - os.Put(static_cast(0x00u)); - } - - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(c & 0xFFu)); - os.Put(static_cast((c >> 8) & 0xFFu)); - os.Put(static_cast((c >> 16) & 0xFFu)); - os.Put(static_cast((c >> 24) & 0xFFu)); - } -}; - -//! UTF-32 big endian encoding. -template -struct UTF32BE : UTF32 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return static_cast(c) == 0x0000FEFFu ? Take(is) : c; - } - - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - unsigned c = static_cast(static_cast(is.Take())) << 24; - c |= static_cast(static_cast(is.Take())) << 16; - c |= static_cast(static_cast(is.Take())) << 8; - c |= static_cast(static_cast(is.Take())); - return static_cast(c); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(0x00u)); - os.Put(static_cast(0x00u)); - os.Put(static_cast(0xFEu)); - os.Put(static_cast(0xFFu)); - } - - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast((c >> 24) & 0xFFu)); - os.Put(static_cast((c >> 16) & 0xFFu)); - os.Put(static_cast((c >> 8) & 0xFFu)); - os.Put(static_cast(c & 0xFFu)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// ASCII - -//! ASCII encoding. -/*! http://en.wikipedia.org/wiki/ASCII - \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. - \note implements Encoding concept -*/ -template -struct ASCII { - typedef CharType Ch; - - enum { supportUnicode = 0 }; - - template - static void Encode(OutputStream& os, unsigned codepoint) { - RAPIDJSON_ASSERT(codepoint <= 0x7F); - os.Put(static_cast(codepoint & 0xFF)); - } - - template - static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - RAPIDJSON_ASSERT(codepoint <= 0x7F); - PutUnsafe(os, static_cast(codepoint & 0xFF)); - } - - template - static bool Decode(InputStream& is, unsigned* codepoint) { - uint8_t c = static_cast(is.Take()); - *codepoint = c; - return c <= 0X7F; - } - - template - static bool Validate(InputStream& is, OutputStream& os) { - uint8_t c = static_cast(is.Take()); - os.Put(static_cast(c)); - return c <= 0x7F; - } - - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - uint8_t c = static_cast(Take(is)); - return static_cast(c); - } - - template - static Ch Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - return static_cast(is.Take()); - } - - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - (void)os; - } - - template - static void Put(OutputByteStream& os, Ch c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(c)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// AutoUTF - -//! Runtime-specified UTF encoding type of a stream. -enum UTFType { - kUTF8 = 0, //!< UTF-8. - kUTF16LE = 1, //!< UTF-16 little endian. - kUTF16BE = 2, //!< UTF-16 big endian. - kUTF32LE = 3, //!< UTF-32 little endian. - kUTF32BE = 4 //!< UTF-32 big endian. -}; - -//! Dynamically select encoding according to stream's runtime-specified UTF encoding type. -/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType(). -*/ -template -struct AutoUTF { - typedef CharType Ch; - - enum { supportUnicode = 1 }; - -#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x - - template - RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { - typedef void (*EncodeFunc)(OutputStream&, unsigned); - static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; - (*f[os.GetType()])(os, codepoint); - } - - template - RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { - typedef void (*EncodeFunc)(OutputStream&, unsigned); - static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; - (*f[os.GetType()])(os, codepoint); - } - - template - RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { - typedef bool (*DecodeFunc)(InputStream&, unsigned*); - static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; - return (*f[is.GetType()])(is, codepoint); - } - - template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { - typedef bool (*ValidateFunc)(InputStream&, OutputStream&); - static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; - return (*f[is.GetType()])(is, os); - } - -#undef RAPIDJSON_ENCODINGS_FUNC -}; - -/////////////////////////////////////////////////////////////////////////////// -// Transcoder - -//! Encoding conversion. -template -struct Transcoder { - //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. - template - RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { - unsigned codepoint; - if (!SourceEncoding::Decode(is, &codepoint)) - return false; - TargetEncoding::Encode(os, codepoint); - return true; - } - - template - RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { - unsigned codepoint; - if (!SourceEncoding::Decode(is, &codepoint)) - return false; - TargetEncoding::EncodeUnsafe(os, codepoint); - return true; - } - - //! Validate one Unicode codepoint from an encoded stream. - template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { - return Transcode(is, os); // Since source/target encoding is different, must transcode. - } -}; - -// Forward declaration. -template -inline void PutUnsafe(Stream& stream, typename Stream::Ch c); - -//! Specialization of Transcoder with same source and target encoding. -template -struct Transcoder { - template - RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { - os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. - return true; - } - - template - RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { - PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. - return true; - } - - template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { - return Encoding::Validate(is, os); // source/target encoding are the same - } -}; - -RAPIDJSON_NAMESPACE_END - -#if defined(__GNUC__) || defined(_MSC_VER) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/error/en.h b/src/Native/libcryptonight/3rdparty/rapidjson/error/en.h deleted file mode 100644 index 2db838bff..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/error/en.h +++ /dev/null @@ -1,74 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ERROR_EN_H_ -#define RAPIDJSON_ERROR_EN_H_ - -#include "error.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(switch-enum) -RAPIDJSON_DIAG_OFF(covered-switch-default) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Maps error code of parsing into error message. -/*! - \ingroup RAPIDJSON_ERRORS - \param parseErrorCode Error code obtained in parsing. - \return the error message. - \note User can make a copy of this function for localization. - Using switch-case is safer for future modification of error codes. -*/ -inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { - switch (parseErrorCode) { - case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); - - case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); - case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); - - case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); - - case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); - case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); - case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); - - case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); - - case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); - case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); - case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); - case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); - case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); - - case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); - case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); - case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); - - case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); - case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); - - default: return RAPIDJSON_ERROR_STRING("Unknown error."); - } -} - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_ERROR_EN_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/error/error.h b/src/Native/libcryptonight/3rdparty/rapidjson/error/error.h deleted file mode 100644 index 95cb31a72..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/error/error.h +++ /dev/null @@ -1,155 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ERROR_ERROR_H_ -#define RAPIDJSON_ERROR_ERROR_H_ - -#include "../rapidjson.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -/*! \file error.h */ - -/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ERROR_CHARTYPE - -//! Character type of error messages. -/*! \ingroup RAPIDJSON_ERRORS - The default character type is \c char. - On Windows, user can define this macro as \c TCHAR for supporting both - unicode/non-unicode settings. -*/ -#ifndef RAPIDJSON_ERROR_CHARTYPE -#define RAPIDJSON_ERROR_CHARTYPE char -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ERROR_STRING - -//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. -/*! \ingroup RAPIDJSON_ERRORS - By default this conversion macro does nothing. - On Windows, user can define this macro as \c _T(x) for supporting both - unicode/non-unicode settings. -*/ -#ifndef RAPIDJSON_ERROR_STRING -#define RAPIDJSON_ERROR_STRING(x) x -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// ParseErrorCode - -//! Error code of parsing. -/*! \ingroup RAPIDJSON_ERRORS - \see GenericReader::Parse, GenericReader::GetParseErrorCode -*/ -enum ParseErrorCode { - kParseErrorNone = 0, //!< No error. - - kParseErrorDocumentEmpty, //!< The document is empty. - kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. - - kParseErrorValueInvalid, //!< Invalid value. - - kParseErrorObjectMissName, //!< Missing a name for object member. - kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. - kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. - - kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. - - kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. - kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. - kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. - kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. - kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. - - kParseErrorNumberTooBig, //!< Number too big to be stored in double. - kParseErrorNumberMissFraction, //!< Miss fraction part in number. - kParseErrorNumberMissExponent, //!< Miss exponent in number. - - kParseErrorTermination, //!< Parsing was terminated. - kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. -}; - -//! Result of parsing (wraps ParseErrorCode) -/*! - \ingroup RAPIDJSON_ERRORS - \code - Document doc; - ParseResult ok = doc.Parse("[42]"); - if (!ok) { - fprintf(stderr, "JSON parse error: %s (%u)", - GetParseError_En(ok.Code()), ok.Offset()); - exit(EXIT_FAILURE); - } - \endcode - \see GenericReader::Parse, GenericDocument::Parse -*/ -struct ParseResult { -public: - //! Default constructor, no error. - ParseResult() : code_(kParseErrorNone), offset_(0) {} - //! Constructor to set an error. - ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} - - //! Get the error code. - ParseErrorCode Code() const { return code_; } - //! Get the error offset, if \ref IsError(), 0 otherwise. - size_t Offset() const { return offset_; } - - //! Conversion to \c bool, returns \c true, iff !\ref IsError(). - operator bool() const { return !IsError(); } - //! Whether the result is an error. - bool IsError() const { return code_ != kParseErrorNone; } - - bool operator==(const ParseResult& that) const { return code_ == that.code_; } - bool operator==(ParseErrorCode code) const { return code_ == code; } - friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } - - //! Reset error code. - void Clear() { Set(kParseErrorNone); } - //! Update error code and offset. - void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } - -private: - ParseErrorCode code_; - size_t offset_; -}; - -//! Function pointer type of GetParseError(). -/*! \ingroup RAPIDJSON_ERRORS - - This is the prototype for \c GetParseError_X(), where \c X is a locale. - User can dynamically change locale in runtime, e.g.: -\code - GetParseErrorFunc GetParseError = GetParseError_En; // or whatever - const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); -\endcode -*/ -typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_ERROR_ERROR_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/filereadstream.h b/src/Native/libcryptonight/3rdparty/rapidjson/filereadstream.h deleted file mode 100644 index b56ea13b3..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/filereadstream.h +++ /dev/null @@ -1,99 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_FILEREADSTREAM_H_ -#define RAPIDJSON_FILEREADSTREAM_H_ - -#include "stream.h" -#include - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(unreachable-code) -RAPIDJSON_DIAG_OFF(missing-noreturn) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! File byte stream for input using fread(). -/*! - \note implements Stream concept -*/ -class FileReadStream { -public: - typedef char Ch; //!< Character type (byte). - - //! Constructor. - /*! - \param fp File pointer opened for read. - \param buffer user-supplied buffer. - \param bufferSize size of buffer in bytes. Must >=4 bytes. - */ - FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { - RAPIDJSON_ASSERT(fp_ != 0); - RAPIDJSON_ASSERT(bufferSize >= 4); - Read(); - } - - Ch Peek() const { return *current_; } - Ch Take() { Ch c = *current_; Read(); return c; } - size_t Tell() const { return count_ + static_cast(current_ - buffer_); } - - // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - - // For encoding detection only. - const Ch* Peek4() const { - return (current_ + 4 <= bufferLast_) ? current_ : 0; - } - -private: - void Read() { - if (current_ < bufferLast_) - ++current_; - else if (!eof_) { - count_ += readCount_; - readCount_ = fread(buffer_, 1, bufferSize_, fp_); - bufferLast_ = buffer_ + readCount_ - 1; - current_ = buffer_; - - if (readCount_ < bufferSize_) { - buffer_[readCount_] = '\0'; - ++bufferLast_; - eof_ = true; - } - } - } - - std::FILE* fp_; - Ch *buffer_; - size_t bufferSize_; - Ch *bufferLast_; - Ch *current_; - size_t readCount_; - size_t count_; //!< Number of characters read - bool eof_; -}; - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/filewritestream.h b/src/Native/libcryptonight/3rdparty/rapidjson/filewritestream.h deleted file mode 100644 index 6378dd60e..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/filewritestream.h +++ /dev/null @@ -1,104 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_FILEWRITESTREAM_H_ -#define RAPIDJSON_FILEWRITESTREAM_H_ - -#include "stream.h" -#include - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(unreachable-code) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Wrapper of C file stream for input using fread(). -/*! - \note implements Stream concept -*/ -class FileWriteStream { -public: - typedef char Ch; //!< Character type. Only support char. - - FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { - RAPIDJSON_ASSERT(fp_ != 0); - } - - void Put(char c) { - if (current_ >= bufferEnd_) - Flush(); - - *current_++ = c; - } - - void PutN(char c, size_t n) { - size_t avail = static_cast(bufferEnd_ - current_); - while (n > avail) { - std::memset(current_, c, avail); - current_ += avail; - Flush(); - n -= avail; - avail = static_cast(bufferEnd_ - current_); - } - - if (n > 0) { - std::memset(current_, c, n); - current_ += n; - } - } - - void Flush() { - if (current_ != buffer_) { - size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); - if (result < static_cast(current_ - buffer_)) { - // failure deliberately ignored at this time - // added to avoid warn_unused_result build errors - } - current_ = buffer_; - } - } - - // Not implemented - char Peek() const { RAPIDJSON_ASSERT(false); return 0; } - char Take() { RAPIDJSON_ASSERT(false); return 0; } - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - // Prohibit copy constructor & assignment operator. - FileWriteStream(const FileWriteStream&); - FileWriteStream& operator=(const FileWriteStream&); - - std::FILE* fp_; - char *buffer_; - char *bufferEnd_; - char *current_; -}; - -//! Implement specialized version of PutN() with memset() for better performance. -template<> -inline void PutN(FileWriteStream& stream, char c, size_t n) { - stream.PutN(c, n); -} - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/fwd.h b/src/Native/libcryptonight/3rdparty/rapidjson/fwd.h deleted file mode 100644 index e8104e841..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/fwd.h +++ /dev/null @@ -1,151 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_FWD_H_ -#define RAPIDJSON_FWD_H_ - -#include "rapidjson.h" - -RAPIDJSON_NAMESPACE_BEGIN - -// encodings.h - -template struct UTF8; -template struct UTF16; -template struct UTF16BE; -template struct UTF16LE; -template struct UTF32; -template struct UTF32BE; -template struct UTF32LE; -template struct ASCII; -template struct AutoUTF; - -template -struct Transcoder; - -// allocators.h - -class CrtAllocator; - -template -class MemoryPoolAllocator; - -// stream.h - -template -struct GenericStringStream; - -typedef GenericStringStream > StringStream; - -template -struct GenericInsituStringStream; - -typedef GenericInsituStringStream > InsituStringStream; - -// stringbuffer.h - -template -class GenericStringBuffer; - -typedef GenericStringBuffer, CrtAllocator> StringBuffer; - -// filereadstream.h - -class FileReadStream; - -// filewritestream.h - -class FileWriteStream; - -// memorybuffer.h - -template -struct GenericMemoryBuffer; - -typedef GenericMemoryBuffer MemoryBuffer; - -// memorystream.h - -struct MemoryStream; - -// reader.h - -template -struct BaseReaderHandler; - -template -class GenericReader; - -typedef GenericReader, UTF8, CrtAllocator> Reader; - -// writer.h - -template -class Writer; - -// prettywriter.h - -template -class PrettyWriter; - -// document.h - -template -struct GenericMember; - -template -class GenericMemberIterator; - -template -struct GenericStringRef; - -template -class GenericValue; - -typedef GenericValue, MemoryPoolAllocator > Value; - -template -class GenericDocument; - -typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; - -// pointer.h - -template -class GenericPointer; - -typedef GenericPointer Pointer; - -// schema.h - -template -class IGenericRemoteSchemaDocumentProvider; - -template -class GenericSchemaDocument; - -typedef GenericSchemaDocument SchemaDocument; -typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; - -template < - typename SchemaDocumentType, - typename OutputHandler, - typename StateAllocator> -class GenericSchemaValidator; - -typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_RAPIDJSONFWD_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/internal/biginteger.h b/src/Native/libcryptonight/3rdparty/rapidjson/internal/biginteger.h deleted file mode 100644 index 9d3e88c99..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/internal/biginteger.h +++ /dev/null @@ -1,290 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_BIGINTEGER_H_ -#define RAPIDJSON_BIGINTEGER_H_ - -#include "../rapidjson.h" - -#if defined(_MSC_VER) && defined(_M_AMD64) -#include // for _umul128 -#pragma intrinsic(_umul128) -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -class BigInteger { -public: - typedef uint64_t Type; - - BigInteger(const BigInteger& rhs) : count_(rhs.count_) { - std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); - } - - explicit BigInteger(uint64_t u) : count_(1) { - digits_[0] = u; - } - - BigInteger(const char* decimals, size_t length) : count_(1) { - RAPIDJSON_ASSERT(length > 0); - digits_[0] = 0; - size_t i = 0; - const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 - while (length >= kMaxDigitPerIteration) { - AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); - length -= kMaxDigitPerIteration; - i += kMaxDigitPerIteration; - } - - if (length > 0) - AppendDecimal64(decimals + i, decimals + i + length); - } - - BigInteger& operator=(const BigInteger &rhs) - { - if (this != &rhs) { - count_ = rhs.count_; - std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); - } - return *this; - } - - BigInteger& operator=(uint64_t u) { - digits_[0] = u; - count_ = 1; - return *this; - } - - BigInteger& operator+=(uint64_t u) { - Type backup = digits_[0]; - digits_[0] += u; - for (size_t i = 0; i < count_ - 1; i++) { - if (digits_[i] >= backup) - return *this; // no carry - backup = digits_[i + 1]; - digits_[i + 1] += 1; - } - - // Last carry - if (digits_[count_ - 1] < backup) - PushBack(1); - - return *this; - } - - BigInteger& operator*=(uint64_t u) { - if (u == 0) return *this = 0; - if (u == 1) return *this; - if (*this == 1) return *this = u; - - uint64_t k = 0; - for (size_t i = 0; i < count_; i++) { - uint64_t hi; - digits_[i] = MulAdd64(digits_[i], u, k, &hi); - k = hi; - } - - if (k > 0) - PushBack(k); - - return *this; - } - - BigInteger& operator*=(uint32_t u) { - if (u == 0) return *this = 0; - if (u == 1) return *this; - if (*this == 1) return *this = u; - - uint64_t k = 0; - for (size_t i = 0; i < count_; i++) { - const uint64_t c = digits_[i] >> 32; - const uint64_t d = digits_[i] & 0xFFFFFFFF; - const uint64_t uc = u * c; - const uint64_t ud = u * d; - const uint64_t p0 = ud + k; - const uint64_t p1 = uc + (p0 >> 32); - digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32); - k = p1 >> 32; - } - - if (k > 0) - PushBack(k); - - return *this; - } - - BigInteger& operator<<=(size_t shift) { - if (IsZero() || shift == 0) return *this; - - size_t offset = shift / kTypeBit; - size_t interShift = shift % kTypeBit; - RAPIDJSON_ASSERT(count_ + offset <= kCapacity); - - if (interShift == 0) { - std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type)); - count_ += offset; - } - else { - digits_[count_] = 0; - for (size_t i = count_; i > 0; i--) - digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift)); - digits_[offset] = digits_[0] << interShift; - count_ += offset; - if (digits_[count_]) - count_++; - } - - std::memset(digits_, 0, offset * sizeof(Type)); - - return *this; - } - - bool operator==(const BigInteger& rhs) const { - return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; - } - - bool operator==(const Type rhs) const { - return count_ == 1 && digits_[0] == rhs; - } - - BigInteger& MultiplyPow5(unsigned exp) { - static const uint32_t kPow5[12] = { - 5, - 5 * 5, - 5 * 5 * 5, - 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 - }; - if (exp == 0) return *this; - for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 - for (; exp >= 13; exp -= 13) *this *= static_cast(1220703125u); // 5^13 - if (exp > 0) *this *= kPow5[exp - 1]; - return *this; - } - - // Compute absolute difference of this and rhs. - // Assume this != rhs - bool Difference(const BigInteger& rhs, BigInteger* out) const { - int cmp = Compare(rhs); - RAPIDJSON_ASSERT(cmp != 0); - const BigInteger *a, *b; // Makes a > b - bool ret; - if (cmp < 0) { a = &rhs; b = this; ret = true; } - else { a = this; b = &rhs; ret = false; } - - Type borrow = 0; - for (size_t i = 0; i < a->count_; i++) { - Type d = a->digits_[i] - borrow; - if (i < b->count_) - d -= b->digits_[i]; - borrow = (d > a->digits_[i]) ? 1 : 0; - out->digits_[i] = d; - if (d != 0) - out->count_ = i + 1; - } - - return ret; - } - - int Compare(const BigInteger& rhs) const { - if (count_ != rhs.count_) - return count_ < rhs.count_ ? -1 : 1; - - for (size_t i = count_; i-- > 0;) - if (digits_[i] != rhs.digits_[i]) - return digits_[i] < rhs.digits_[i] ? -1 : 1; - - return 0; - } - - size_t GetCount() const { return count_; } - Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; } - bool IsZero() const { return count_ == 1 && digits_[0] == 0; } - -private: - void AppendDecimal64(const char* begin, const char* end) { - uint64_t u = ParseUint64(begin, end); - if (IsZero()) - *this = u; - else { - unsigned exp = static_cast(end - begin); - (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u - } - } - - void PushBack(Type digit) { - RAPIDJSON_ASSERT(count_ < kCapacity); - digits_[count_++] = digit; - } - - static uint64_t ParseUint64(const char* begin, const char* end) { - uint64_t r = 0; - for (const char* p = begin; p != end; ++p) { - RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); - r = r * 10u + static_cast(*p - '0'); - } - return r; - } - - // Assume a * b + k < 2^128 - static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) { -#if defined(_MSC_VER) && defined(_M_AMD64) - uint64_t low = _umul128(a, b, outHigh) + k; - if (low < k) - (*outHigh)++; - return low; -#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) - __extension__ typedef unsigned __int128 uint128; - uint128 p = static_cast(a) * static_cast(b); - p += k; - *outHigh = static_cast(p >> 64); - return static_cast(p); -#else - const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; - uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1; - x1 += (x0 >> 32); // can't give carry - x1 += x2; - if (x1 < x2) - x3 += (static_cast(1) << 32); - uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); - uint64_t hi = x3 + (x1 >> 32); - - lo += k; - if (lo < k) - hi++; - *outHigh = hi; - return lo; -#endif - } - - static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 - static const size_t kCapacity = kBitCount / sizeof(Type); - static const size_t kTypeBit = sizeof(Type) * 8; - - Type digits_[kCapacity]; - size_t count_; -}; - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_BIGINTEGER_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/internal/diyfp.h b/src/Native/libcryptonight/3rdparty/rapidjson/internal/diyfp.h deleted file mode 100644 index c9fefdc61..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/internal/diyfp.h +++ /dev/null @@ -1,258 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -// This is a C++ header-only implementation of Grisu2 algorithm from the publication: -// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with -// integers." ACM Sigplan Notices 45.6 (2010): 233-243. - -#ifndef RAPIDJSON_DIYFP_H_ -#define RAPIDJSON_DIYFP_H_ - -#include "../rapidjson.h" - -#if defined(_MSC_VER) && defined(_M_AMD64) -#include -#pragma intrinsic(_BitScanReverse64) -#pragma intrinsic(_umul128) -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -struct DiyFp { - DiyFp() : f(), e() {} - - DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} - - explicit DiyFp(double d) { - union { - double d; - uint64_t u64; - } u = { d }; - - int biased_e = static_cast((u.u64 & kDpExponentMask) >> kDpSignificandSize); - uint64_t significand = (u.u64 & kDpSignificandMask); - if (biased_e != 0) { - f = significand + kDpHiddenBit; - e = biased_e - kDpExponentBias; - } - else { - f = significand; - e = kDpMinExponent + 1; - } - } - - DiyFp operator-(const DiyFp& rhs) const { - return DiyFp(f - rhs.f, e); - } - - DiyFp operator*(const DiyFp& rhs) const { -#if defined(_MSC_VER) && defined(_M_AMD64) - uint64_t h; - uint64_t l = _umul128(f, rhs.f, &h); - if (l & (uint64_t(1) << 63)) // rounding - h++; - return DiyFp(h, e + rhs.e + 64); -#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) - __extension__ typedef unsigned __int128 uint128; - uint128 p = static_cast(f) * static_cast(rhs.f); - uint64_t h = static_cast(p >> 64); - uint64_t l = static_cast(p); - if (l & (uint64_t(1) << 63)) // rounding - h++; - return DiyFp(h, e + rhs.e + 64); -#else - const uint64_t M32 = 0xFFFFFFFF; - const uint64_t a = f >> 32; - const uint64_t b = f & M32; - const uint64_t c = rhs.f >> 32; - const uint64_t d = rhs.f & M32; - const uint64_t ac = a * c; - const uint64_t bc = b * c; - const uint64_t ad = a * d; - const uint64_t bd = b * d; - uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); - tmp += 1U << 31; /// mult_round - return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); -#endif - } - - DiyFp Normalize() const { -#if defined(_MSC_VER) && defined(_M_AMD64) - unsigned long index; - _BitScanReverse64(&index, f); - return DiyFp(f << (63 - index), e - (63 - index)); -#elif defined(__GNUC__) && __GNUC__ >= 4 - int s = __builtin_clzll(f); - return DiyFp(f << s, e - s); -#else - DiyFp res = *this; - while (!(res.f & (static_cast(1) << 63))) { - res.f <<= 1; - res.e--; - } - return res; -#endif - } - - DiyFp NormalizeBoundary() const { - DiyFp res = *this; - while (!(res.f & (kDpHiddenBit << 1))) { - res.f <<= 1; - res.e--; - } - res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); - res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); - return res; - } - - void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { - DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); - DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); - mi.f <<= mi.e - pl.e; - mi.e = pl.e; - *plus = pl; - *minus = mi; - } - - double ToDouble() const { - union { - double d; - uint64_t u64; - }u; - const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : - static_cast(e + kDpExponentBias); - u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); - return u.d; - } - - static const int kDiySignificandSize = 64; - static const int kDpSignificandSize = 52; - static const int kDpExponentBias = 0x3FF + kDpSignificandSize; - static const int kDpMaxExponent = 0x7FF - kDpExponentBias; - static const int kDpMinExponent = -kDpExponentBias; - static const int kDpDenormalExponent = -kDpExponentBias + 1; - static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); - static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); - static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); - - uint64_t f; - int e; -}; - -inline DiyFp GetCachedPowerByIndex(size_t index) { - // 10^-348, 10^-340, ..., 10^340 - static const uint64_t kCachedPowers_F[] = { - RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), - RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), - RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), - RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), - RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), - RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), - RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), - RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), - RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), - RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), - RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), - RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), - RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), - RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), - RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), - RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), - RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), - RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), - RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), - RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), - RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), - RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), - RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), - RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), - RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), - RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), - RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), - RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), - RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), - RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), - RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), - RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), - RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), - RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), - RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), - RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), - RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), - RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), - RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), - RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), - RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), - RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), - RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), - RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) - }; - static const int16_t kCachedPowers_E[] = { - -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, - -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, - -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, - -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, - -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, - 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, - 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, - 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, - 907, 933, 960, 986, 1013, 1039, 1066 - }; - return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); -} - -inline DiyFp GetCachedPower(int e, int* K) { - - //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; - double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive - int k = static_cast(dk); - if (dk - k > 0.0) - k++; - - unsigned index = static_cast((k >> 3) + 1); - *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table - - return GetCachedPowerByIndex(index); -} - -inline DiyFp GetCachedPower10(int exp, int *outExp) { - unsigned index = (static_cast(exp) + 348u) / 8u; - *outExp = -348 + static_cast(index) * 8; - return GetCachedPowerByIndex(index); - } - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -RAPIDJSON_DIAG_OFF(padded) -#endif - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_DIYFP_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/internal/dtoa.h b/src/Native/libcryptonight/3rdparty/rapidjson/internal/dtoa.h deleted file mode 100644 index 8d6350e62..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/internal/dtoa.h +++ /dev/null @@ -1,245 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -// This is a C++ header-only implementation of Grisu2 algorithm from the publication: -// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with -// integers." ACM Sigplan Notices 45.6 (2010): 233-243. - -#ifndef RAPIDJSON_DTOA_ -#define RAPIDJSON_DTOA_ - -#include "itoa.h" // GetDigitsLut() -#include "diyfp.h" -#include "ieee754.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 -#endif - -inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { - while (rest < wp_w && delta - rest >= ten_kappa && - (rest + ten_kappa < wp_w || /// closer - wp_w - rest > rest + ten_kappa - wp_w)) { - buffer[len - 1]--; - rest += ten_kappa; - } -} - -inline unsigned CountDecimalDigit32(uint32_t n) { - // Simple pure C++ implementation was faster than __builtin_clz version in this situation. - if (n < 10) return 1; - if (n < 100) return 2; - if (n < 1000) return 3; - if (n < 10000) return 4; - if (n < 100000) return 5; - if (n < 1000000) return 6; - if (n < 10000000) return 7; - if (n < 100000000) return 8; - // Will not reach 10 digits in DigitGen() - //if (n < 1000000000) return 9; - //return 10; - return 9; -} - -inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { - static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; - const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); - const DiyFp wp_w = Mp - W; - uint32_t p1 = static_cast(Mp.f >> -one.e); - uint64_t p2 = Mp.f & (one.f - 1); - unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] - *len = 0; - - while (kappa > 0) { - uint32_t d = 0; - switch (kappa) { - case 9: d = p1 / 100000000; p1 %= 100000000; break; - case 8: d = p1 / 10000000; p1 %= 10000000; break; - case 7: d = p1 / 1000000; p1 %= 1000000; break; - case 6: d = p1 / 100000; p1 %= 100000; break; - case 5: d = p1 / 10000; p1 %= 10000; break; - case 4: d = p1 / 1000; p1 %= 1000; break; - case 3: d = p1 / 100; p1 %= 100; break; - case 2: d = p1 / 10; p1 %= 10; break; - case 1: d = p1; p1 = 0; break; - default:; - } - if (d || *len) - buffer[(*len)++] = static_cast('0' + static_cast(d)); - kappa--; - uint64_t tmp = (static_cast(p1) << -one.e) + p2; - if (tmp <= delta) { - *K += kappa; - GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); - return; - } - } - - // kappa = 0 - for (;;) { - p2 *= 10; - delta *= 10; - char d = static_cast(p2 >> -one.e); - if (d || *len) - buffer[(*len)++] = static_cast('0' + d); - p2 &= one.f - 1; - kappa--; - if (p2 < delta) { - *K += kappa; - int index = -static_cast(kappa); - GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast(kappa)] : 0)); - return; - } - } -} - -inline void Grisu2(double value, char* buffer, int* length, int* K) { - const DiyFp v(value); - DiyFp w_m, w_p; - v.NormalizedBoundaries(&w_m, &w_p); - - const DiyFp c_mk = GetCachedPower(w_p.e, K); - const DiyFp W = v.Normalize() * c_mk; - DiyFp Wp = w_p * c_mk; - DiyFp Wm = w_m * c_mk; - Wm.f++; - Wp.f--; - DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); -} - -inline char* WriteExponent(int K, char* buffer) { - if (K < 0) { - *buffer++ = '-'; - K = -K; - } - - if (K >= 100) { - *buffer++ = static_cast('0' + static_cast(K / 100)); - K %= 100; - const char* d = GetDigitsLut() + K * 2; - *buffer++ = d[0]; - *buffer++ = d[1]; - } - else if (K >= 10) { - const char* d = GetDigitsLut() + K * 2; - *buffer++ = d[0]; - *buffer++ = d[1]; - } - else - *buffer++ = static_cast('0' + static_cast(K)); - - return buffer; -} - -inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { - const int kk = length + k; // 10^(kk-1) <= v < 10^kk - - if (0 <= k && kk <= 21) { - // 1234e7 -> 12340000000 - for (int i = length; i < kk; i++) - buffer[i] = '0'; - buffer[kk] = '.'; - buffer[kk + 1] = '0'; - return &buffer[kk + 2]; - } - else if (0 < kk && kk <= 21) { - // 1234e-2 -> 12.34 - std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); - buffer[kk] = '.'; - if (0 > k + maxDecimalPlaces) { - // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 - // Remove extra trailing zeros (at least one) after truncation. - for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) - if (buffer[i] != '0') - return &buffer[i + 1]; - return &buffer[kk + 2]; // Reserve one zero - } - else - return &buffer[length + 1]; - } - else if (-6 < kk && kk <= 0) { - // 1234e-6 -> 0.001234 - const int offset = 2 - kk; - std::memmove(&buffer[offset], &buffer[0], static_cast(length)); - buffer[0] = '0'; - buffer[1] = '.'; - for (int i = 2; i < offset; i++) - buffer[i] = '0'; - if (length - kk > maxDecimalPlaces) { - // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 - // Remove extra trailing zeros (at least one) after truncation. - for (int i = maxDecimalPlaces + 1; i > 2; i--) - if (buffer[i] != '0') - return &buffer[i + 1]; - return &buffer[3]; // Reserve one zero - } - else - return &buffer[length + offset]; - } - else if (kk < -maxDecimalPlaces) { - // Truncate to zero - buffer[0] = '0'; - buffer[1] = '.'; - buffer[2] = '0'; - return &buffer[3]; - } - else if (length == 1) { - // 1e30 - buffer[1] = 'e'; - return WriteExponent(kk - 1, &buffer[2]); - } - else { - // 1234e30 -> 1.234e33 - std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); - buffer[1] = '.'; - buffer[length + 1] = 'e'; - return WriteExponent(kk - 1, &buffer[0 + length + 2]); - } -} - -inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { - RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); - Double d(value); - if (d.IsZero()) { - if (d.Sign()) - *buffer++ = '-'; // -0.0, Issue #289 - buffer[0] = '0'; - buffer[1] = '.'; - buffer[2] = '0'; - return &buffer[3]; - } - else { - if (value < 0) { - *buffer++ = '-'; - value = -value; - } - int length, K; - Grisu2(value, buffer, &length, &K); - return Prettify(buffer, length, K, maxDecimalPlaces); - } -} - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_DTOA_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/internal/ieee754.h b/src/Native/libcryptonight/3rdparty/rapidjson/internal/ieee754.h deleted file mode 100644 index 82bb0b99e..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/internal/ieee754.h +++ /dev/null @@ -1,78 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_IEEE754_ -#define RAPIDJSON_IEEE754_ - -#include "../rapidjson.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -class Double { -public: - Double() {} - Double(double d) : d_(d) {} - Double(uint64_t u) : u_(u) {} - - double Value() const { return d_; } - uint64_t Uint64Value() const { return u_; } - - double NextPositiveDouble() const { - RAPIDJSON_ASSERT(!Sign()); - return Double(u_ + 1).Value(); - } - - bool Sign() const { return (u_ & kSignMask) != 0; } - uint64_t Significand() const { return u_ & kSignificandMask; } - int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } - - bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } - bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } - bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } - bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } - bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } - - uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } - int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } - uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } - - static unsigned EffectiveSignificandSize(int order) { - if (order >= -1021) - return 53; - else if (order <= -1074) - return 0; - else - return static_cast(order) + 1074; - } - -private: - static const int kSignificandSize = 52; - static const int kExponentBias = 0x3FF; - static const int kDenormalExponent = 1 - kExponentBias; - static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); - static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); - static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); - static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); - - union { - double d_; - uint64_t u_; - }; -}; - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_IEEE754_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/internal/itoa.h b/src/Native/libcryptonight/3rdparty/rapidjson/internal/itoa.h deleted file mode 100644 index 01a4e7e72..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/internal/itoa.h +++ /dev/null @@ -1,304 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ITOA_ -#define RAPIDJSON_ITOA_ - -#include "../rapidjson.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -inline const char* GetDigitsLut() { - static const char cDigitsLut[200] = { - '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', - '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', - '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', - '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', - '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', - '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', - '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', - '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', - '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', - '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' - }; - return cDigitsLut; -} - -inline char* u32toa(uint32_t value, char* buffer) { - const char* cDigitsLut = GetDigitsLut(); - - if (value < 10000) { - const uint32_t d1 = (value / 100) << 1; - const uint32_t d2 = (value % 100) << 1; - - if (value >= 1000) - *buffer++ = cDigitsLut[d1]; - if (value >= 100) - *buffer++ = cDigitsLut[d1 + 1]; - if (value >= 10) - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - } - else if (value < 100000000) { - // value = bbbbcccc - const uint32_t b = value / 10000; - const uint32_t c = value % 10000; - - const uint32_t d1 = (b / 100) << 1; - const uint32_t d2 = (b % 100) << 1; - - const uint32_t d3 = (c / 100) << 1; - const uint32_t d4 = (c % 100) << 1; - - if (value >= 10000000) - *buffer++ = cDigitsLut[d1]; - if (value >= 1000000) - *buffer++ = cDigitsLut[d1 + 1]; - if (value >= 100000) - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - - *buffer++ = cDigitsLut[d3]; - *buffer++ = cDigitsLut[d3 + 1]; - *buffer++ = cDigitsLut[d4]; - *buffer++ = cDigitsLut[d4 + 1]; - } - else { - // value = aabbbbcccc in decimal - - const uint32_t a = value / 100000000; // 1 to 42 - value %= 100000000; - - if (a >= 10) { - const unsigned i = a << 1; - *buffer++ = cDigitsLut[i]; - *buffer++ = cDigitsLut[i + 1]; - } - else - *buffer++ = static_cast('0' + static_cast(a)); - - const uint32_t b = value / 10000; // 0 to 9999 - const uint32_t c = value % 10000; // 0 to 9999 - - const uint32_t d1 = (b / 100) << 1; - const uint32_t d2 = (b % 100) << 1; - - const uint32_t d3 = (c / 100) << 1; - const uint32_t d4 = (c % 100) << 1; - - *buffer++ = cDigitsLut[d1]; - *buffer++ = cDigitsLut[d1 + 1]; - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - *buffer++ = cDigitsLut[d3]; - *buffer++ = cDigitsLut[d3 + 1]; - *buffer++ = cDigitsLut[d4]; - *buffer++ = cDigitsLut[d4 + 1]; - } - return buffer; -} - -inline char* i32toa(int32_t value, char* buffer) { - uint32_t u = static_cast(value); - if (value < 0) { - *buffer++ = '-'; - u = ~u + 1; - } - - return u32toa(u, buffer); -} - -inline char* u64toa(uint64_t value, char* buffer) { - const char* cDigitsLut = GetDigitsLut(); - const uint64_t kTen8 = 100000000; - const uint64_t kTen9 = kTen8 * 10; - const uint64_t kTen10 = kTen8 * 100; - const uint64_t kTen11 = kTen8 * 1000; - const uint64_t kTen12 = kTen8 * 10000; - const uint64_t kTen13 = kTen8 * 100000; - const uint64_t kTen14 = kTen8 * 1000000; - const uint64_t kTen15 = kTen8 * 10000000; - const uint64_t kTen16 = kTen8 * kTen8; - - if (value < kTen8) { - uint32_t v = static_cast(value); - if (v < 10000) { - const uint32_t d1 = (v / 100) << 1; - const uint32_t d2 = (v % 100) << 1; - - if (v >= 1000) - *buffer++ = cDigitsLut[d1]; - if (v >= 100) - *buffer++ = cDigitsLut[d1 + 1]; - if (v >= 10) - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - } - else { - // value = bbbbcccc - const uint32_t b = v / 10000; - const uint32_t c = v % 10000; - - const uint32_t d1 = (b / 100) << 1; - const uint32_t d2 = (b % 100) << 1; - - const uint32_t d3 = (c / 100) << 1; - const uint32_t d4 = (c % 100) << 1; - - if (value >= 10000000) - *buffer++ = cDigitsLut[d1]; - if (value >= 1000000) - *buffer++ = cDigitsLut[d1 + 1]; - if (value >= 100000) - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - - *buffer++ = cDigitsLut[d3]; - *buffer++ = cDigitsLut[d3 + 1]; - *buffer++ = cDigitsLut[d4]; - *buffer++ = cDigitsLut[d4 + 1]; - } - } - else if (value < kTen16) { - const uint32_t v0 = static_cast(value / kTen8); - const uint32_t v1 = static_cast(value % kTen8); - - const uint32_t b0 = v0 / 10000; - const uint32_t c0 = v0 % 10000; - - const uint32_t d1 = (b0 / 100) << 1; - const uint32_t d2 = (b0 % 100) << 1; - - const uint32_t d3 = (c0 / 100) << 1; - const uint32_t d4 = (c0 % 100) << 1; - - const uint32_t b1 = v1 / 10000; - const uint32_t c1 = v1 % 10000; - - const uint32_t d5 = (b1 / 100) << 1; - const uint32_t d6 = (b1 % 100) << 1; - - const uint32_t d7 = (c1 / 100) << 1; - const uint32_t d8 = (c1 % 100) << 1; - - if (value >= kTen15) - *buffer++ = cDigitsLut[d1]; - if (value >= kTen14) - *buffer++ = cDigitsLut[d1 + 1]; - if (value >= kTen13) - *buffer++ = cDigitsLut[d2]; - if (value >= kTen12) - *buffer++ = cDigitsLut[d2 + 1]; - if (value >= kTen11) - *buffer++ = cDigitsLut[d3]; - if (value >= kTen10) - *buffer++ = cDigitsLut[d3 + 1]; - if (value >= kTen9) - *buffer++ = cDigitsLut[d4]; - if (value >= kTen8) - *buffer++ = cDigitsLut[d4 + 1]; - - *buffer++ = cDigitsLut[d5]; - *buffer++ = cDigitsLut[d5 + 1]; - *buffer++ = cDigitsLut[d6]; - *buffer++ = cDigitsLut[d6 + 1]; - *buffer++ = cDigitsLut[d7]; - *buffer++ = cDigitsLut[d7 + 1]; - *buffer++ = cDigitsLut[d8]; - *buffer++ = cDigitsLut[d8 + 1]; - } - else { - const uint32_t a = static_cast(value / kTen16); // 1 to 1844 - value %= kTen16; - - if (a < 10) - *buffer++ = static_cast('0' + static_cast(a)); - else if (a < 100) { - const uint32_t i = a << 1; - *buffer++ = cDigitsLut[i]; - *buffer++ = cDigitsLut[i + 1]; - } - else if (a < 1000) { - *buffer++ = static_cast('0' + static_cast(a / 100)); - - const uint32_t i = (a % 100) << 1; - *buffer++ = cDigitsLut[i]; - *buffer++ = cDigitsLut[i + 1]; - } - else { - const uint32_t i = (a / 100) << 1; - const uint32_t j = (a % 100) << 1; - *buffer++ = cDigitsLut[i]; - *buffer++ = cDigitsLut[i + 1]; - *buffer++ = cDigitsLut[j]; - *buffer++ = cDigitsLut[j + 1]; - } - - const uint32_t v0 = static_cast(value / kTen8); - const uint32_t v1 = static_cast(value % kTen8); - - const uint32_t b0 = v0 / 10000; - const uint32_t c0 = v0 % 10000; - - const uint32_t d1 = (b0 / 100) << 1; - const uint32_t d2 = (b0 % 100) << 1; - - const uint32_t d3 = (c0 / 100) << 1; - const uint32_t d4 = (c0 % 100) << 1; - - const uint32_t b1 = v1 / 10000; - const uint32_t c1 = v1 % 10000; - - const uint32_t d5 = (b1 / 100) << 1; - const uint32_t d6 = (b1 % 100) << 1; - - const uint32_t d7 = (c1 / 100) << 1; - const uint32_t d8 = (c1 % 100) << 1; - - *buffer++ = cDigitsLut[d1]; - *buffer++ = cDigitsLut[d1 + 1]; - *buffer++ = cDigitsLut[d2]; - *buffer++ = cDigitsLut[d2 + 1]; - *buffer++ = cDigitsLut[d3]; - *buffer++ = cDigitsLut[d3 + 1]; - *buffer++ = cDigitsLut[d4]; - *buffer++ = cDigitsLut[d4 + 1]; - *buffer++ = cDigitsLut[d5]; - *buffer++ = cDigitsLut[d5 + 1]; - *buffer++ = cDigitsLut[d6]; - *buffer++ = cDigitsLut[d6 + 1]; - *buffer++ = cDigitsLut[d7]; - *buffer++ = cDigitsLut[d7 + 1]; - *buffer++ = cDigitsLut[d8]; - *buffer++ = cDigitsLut[d8 + 1]; - } - - return buffer; -} - -inline char* i64toa(int64_t value, char* buffer) { - uint64_t u = static_cast(value); - if (value < 0) { - *buffer++ = '-'; - u = ~u + 1; - } - - return u64toa(u, buffer); -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_ITOA_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/internal/meta.h b/src/Native/libcryptonight/3rdparty/rapidjson/internal/meta.h deleted file mode 100644 index 5a9aaa428..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/internal/meta.h +++ /dev/null @@ -1,181 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_META_H_ -#define RAPIDJSON_INTERNAL_META_H_ - -#include "../rapidjson.h" - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif -#if defined(_MSC_VER) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(6334) -#endif - -#if RAPIDJSON_HAS_CXX11_TYPETRAITS -#include -#endif - -//@cond RAPIDJSON_INTERNAL -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching -template struct Void { typedef void Type; }; - -/////////////////////////////////////////////////////////////////////////////// -// BoolType, TrueType, FalseType -// -template struct BoolType { - static const bool Value = Cond; - typedef BoolType Type; -}; -typedef BoolType TrueType; -typedef BoolType FalseType; - - -/////////////////////////////////////////////////////////////////////////////// -// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr -// - -template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; -template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; -template struct SelectIfCond : SelectIfImpl::template Apply {}; -template struct SelectIf : SelectIfCond {}; - -template struct AndExprCond : FalseType {}; -template <> struct AndExprCond : TrueType {}; -template struct OrExprCond : TrueType {}; -template <> struct OrExprCond : FalseType {}; - -template struct BoolExpr : SelectIf::Type {}; -template struct NotExpr : SelectIf::Type {}; -template struct AndExpr : AndExprCond::Type {}; -template struct OrExpr : OrExprCond::Type {}; - - -/////////////////////////////////////////////////////////////////////////////// -// AddConst, MaybeAddConst, RemoveConst -template struct AddConst { typedef const T Type; }; -template struct MaybeAddConst : SelectIfCond {}; -template struct RemoveConst { typedef T Type; }; -template struct RemoveConst { typedef T Type; }; - - -/////////////////////////////////////////////////////////////////////////////// -// IsSame, IsConst, IsMoreConst, IsPointer -// -template struct IsSame : FalseType {}; -template struct IsSame : TrueType {}; - -template struct IsConst : FalseType {}; -template struct IsConst : TrueType {}; - -template -struct IsMoreConst - : AndExpr::Type, typename RemoveConst::Type>, - BoolType::Value >= IsConst::Value> >::Type {}; - -template struct IsPointer : FalseType {}; -template struct IsPointer : TrueType {}; - -/////////////////////////////////////////////////////////////////////////////// -// IsBaseOf -// -#if RAPIDJSON_HAS_CXX11_TYPETRAITS - -template struct IsBaseOf - : BoolType< ::std::is_base_of::value> {}; - -#else // simplified version adopted from Boost - -template struct IsBaseOfImpl { - RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); - RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); - - typedef char (&Yes)[1]; - typedef char (&No) [2]; - - template - static Yes Check(const D*, T); - static No Check(const B*, int); - - struct Host { - operator const B*() const; - operator const D*(); - }; - - enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; -}; - -template struct IsBaseOf - : OrExpr, BoolExpr > >::Type {}; - -#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS - - -////////////////////////////////////////////////////////////////////////// -// EnableIf / DisableIf -// -template struct EnableIfCond { typedef T Type; }; -template struct EnableIfCond { /* empty */ }; - -template struct DisableIfCond { typedef T Type; }; -template struct DisableIfCond { /* empty */ }; - -template -struct EnableIf : EnableIfCond {}; - -template -struct DisableIf : DisableIfCond {}; - -// SFINAE helpers -struct SfinaeTag {}; -template struct RemoveSfinaeTag; -template struct RemoveSfinaeTag { typedef T Type; }; - -#define RAPIDJSON_REMOVEFPTR_(type) \ - typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ - < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type - -#define RAPIDJSON_ENABLEIF(cond) \ - typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ - ::Type * = NULL - -#define RAPIDJSON_DISABLEIF(cond) \ - typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ - ::Type * = NULL - -#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ - typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ - ::Type - -#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ - typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ - ::Type - -} // namespace internal -RAPIDJSON_NAMESPACE_END -//@endcond - -#if defined(__GNUC__) || defined(_MSC_VER) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_INTERNAL_META_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/internal/pow10.h b/src/Native/libcryptonight/3rdparty/rapidjson/internal/pow10.h deleted file mode 100644 index 02f475d70..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/internal/pow10.h +++ /dev/null @@ -1,55 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_POW10_ -#define RAPIDJSON_POW10_ - -#include "../rapidjson.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -//! Computes integer powers of 10 in double (10.0^n). -/*! This function uses lookup table for fast and accurate results. - \param n non-negative exponent. Must <= 308. - \return 10.0^n -*/ -inline double Pow10(int n) { - static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes - 1e+0, - 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, - 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, - 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, - 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, - 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, - 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, - 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, - 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, - 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, - 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, - 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, - 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, - 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, - 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, - 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, - 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 - }; - RAPIDJSON_ASSERT(n >= 0 && n <= 308); - return e[n]; -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_POW10_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/internal/regex.h b/src/Native/libcryptonight/3rdparty/rapidjson/internal/regex.h deleted file mode 100644 index 422a5240b..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/internal/regex.h +++ /dev/null @@ -1,701 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_REGEX_H_ -#define RAPIDJSON_INTERNAL_REGEX_H_ - -#include "../allocators.h" -#include "../stream.h" -#include "stack.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(switch-enum) -RAPIDJSON_DIAG_OFF(implicit-fallthrough) -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#ifdef _MSC_VER -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -#ifndef RAPIDJSON_REGEX_VERBOSE -#define RAPIDJSON_REGEX_VERBOSE 0 -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -/////////////////////////////////////////////////////////////////////////////// -// GenericRegex - -static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 -static const SizeType kRegexInvalidRange = ~SizeType(0); - -//! Regular expression engine with subset of ECMAscript grammar. -/*! - Supported regular expression syntax: - - \c ab Concatenation - - \c a|b Alternation - - \c a? Zero or one - - \c a* Zero or more - - \c a+ One or more - - \c a{3} Exactly 3 times - - \c a{3,} At least 3 times - - \c a{3,5} 3 to 5 times - - \c (ab) Grouping - - \c ^a At the beginning - - \c a$ At the end - - \c . Any character - - \c [abc] Character classes - - \c [a-c] Character class range - - \c [a-z0-9_] Character class combination - - \c [^abc] Negated character classes - - \c [^a-c] Negated character class range - - \c [\b] Backspace (U+0008) - - \c \\| \\\\ ... Escape characters - - \c \\f Form feed (U+000C) - - \c \\n Line feed (U+000A) - - \c \\r Carriage return (U+000D) - - \c \\t Tab (U+0009) - - \c \\v Vertical tab (U+000B) - - \note This is a Thompson NFA engine, implemented with reference to - Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", - https://swtch.com/~rsc/regexp/regexp1.html -*/ -template -class GenericRegex { -public: - typedef typename Encoding::Ch Ch; - - GenericRegex(const Ch* source, Allocator* allocator = 0) : - states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), - stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_() - { - GenericStringStream ss(source); - DecodedStream > ds(ss); - Parse(ds); - } - - ~GenericRegex() { - Allocator::Free(stateSet_); - } - - bool IsValid() const { - return root_ != kRegexInvalidState; - } - - template - bool Match(InputStream& is) const { - return SearchWithAnchoring(is, true, true); - } - - bool Match(const Ch* s) const { - GenericStringStream is(s); - return Match(is); - } - - template - bool Search(InputStream& is) const { - return SearchWithAnchoring(is, anchorBegin_, anchorEnd_); - } - - bool Search(const Ch* s) const { - GenericStringStream is(s); - return Search(is); - } - -private: - enum Operator { - kZeroOrOne, - kZeroOrMore, - kOneOrMore, - kConcatenation, - kAlternation, - kLeftParenthesis - }; - - static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.' - static const unsigned kRangeCharacterClass = 0xFFFFFFFE; - static const unsigned kRangeNegationFlag = 0x80000000; - - struct Range { - unsigned start; // - unsigned end; - SizeType next; - }; - - struct State { - SizeType out; //!< Equals to kInvalid for matching state - SizeType out1; //!< Equals to non-kInvalid for split - SizeType rangeStart; - unsigned codepoint; - }; - - struct Frag { - Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {} - SizeType start; - SizeType out; //!< link-list of all output states - SizeType minIndex; - }; - - template - class DecodedStream { - public: - DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } - unsigned Peek() { return codepoint_; } - unsigned Take() { - unsigned c = codepoint_; - if (c) // No further decoding when '\0' - Decode(); - return c; - } - - private: - void Decode() { - if (!Encoding::Decode(ss_, &codepoint_)) - codepoint_ = 0; - } - - SourceStream& ss_; - unsigned codepoint_; - }; - - State& GetState(SizeType index) { - RAPIDJSON_ASSERT(index < stateCount_); - return states_.template Bottom()[index]; - } - - const State& GetState(SizeType index) const { - RAPIDJSON_ASSERT(index < stateCount_); - return states_.template Bottom()[index]; - } - - Range& GetRange(SizeType index) { - RAPIDJSON_ASSERT(index < rangeCount_); - return ranges_.template Bottom()[index]; - } - - const Range& GetRange(SizeType index) const { - RAPIDJSON_ASSERT(index < rangeCount_); - return ranges_.template Bottom()[index]; - } - - template - void Parse(DecodedStream& ds) { - Allocator allocator; - Stack operandStack(&allocator, 256); // Frag - Stack operatorStack(&allocator, 256); // Operator - Stack atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis) - - *atomCountStack.template Push() = 0; - - unsigned codepoint; - while (ds.Peek() != 0) { - switch (codepoint = ds.Take()) { - case '^': - anchorBegin_ = true; - break; - - case '$': - anchorEnd_ = true; - break; - - case '|': - while (!operatorStack.Empty() && *operatorStack.template Top() < kAlternation) - if (!Eval(operandStack, *operatorStack.template Pop(1))) - return; - *operatorStack.template Push() = kAlternation; - *atomCountStack.template Top() = 0; - break; - - case '(': - *operatorStack.template Push() = kLeftParenthesis; - *atomCountStack.template Push() = 0; - break; - - case ')': - while (!operatorStack.Empty() && *operatorStack.template Top() != kLeftParenthesis) - if (!Eval(operandStack, *operatorStack.template Pop(1))) - return; - if (operatorStack.Empty()) - return; - operatorStack.template Pop(1); - atomCountStack.template Pop(1); - ImplicitConcatenation(atomCountStack, operatorStack); - break; - - case '?': - if (!Eval(operandStack, kZeroOrOne)) - return; - break; - - case '*': - if (!Eval(operandStack, kZeroOrMore)) - return; - break; - - case '+': - if (!Eval(operandStack, kOneOrMore)) - return; - break; - - case '{': - { - unsigned n, m; - if (!ParseUnsigned(ds, &n)) - return; - - if (ds.Peek() == ',') { - ds.Take(); - if (ds.Peek() == '}') - m = kInfinityQuantifier; - else if (!ParseUnsigned(ds, &m) || m < n) - return; - } - else - m = n; - - if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}') - return; - ds.Take(); - } - break; - - case '.': - PushOperand(operandStack, kAnyCharacterClass); - ImplicitConcatenation(atomCountStack, operatorStack); - break; - - case '[': - { - SizeType range; - if (!ParseRange(ds, &range)) - return; - SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass); - GetState(s).rangeStart = range; - *operandStack.template Push() = Frag(s, s, s); - } - ImplicitConcatenation(atomCountStack, operatorStack); - break; - - case '\\': // Escape character - if (!CharacterEscape(ds, &codepoint)) - return; // Unsupported escape character - // fall through to default - - default: // Pattern character - PushOperand(operandStack, codepoint); - ImplicitConcatenation(atomCountStack, operatorStack); - } - } - - while (!operatorStack.Empty()) - if (!Eval(operandStack, *operatorStack.template Pop(1))) - return; - - // Link the operand to matching state. - if (operandStack.GetSize() == sizeof(Frag)) { - Frag* e = operandStack.template Pop(1); - Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0)); - root_ = e->start; - -#if RAPIDJSON_REGEX_VERBOSE - printf("root: %d\n", root_); - for (SizeType i = 0; i < stateCount_ ; i++) { - State& s = GetState(i); - printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint); - } - printf("\n"); -#endif - } - - // Preallocate buffer for SearchWithAnchoring() - RAPIDJSON_ASSERT(stateSet_ == 0); - if (stateCount_ > 0) { - stateSet_ = static_cast(states_.GetAllocator().Malloc(GetStateSetSize())); - state0_.template Reserve(stateCount_); - state1_.template Reserve(stateCount_); - } - } - - SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { - State* s = states_.template Push(); - s->out = out; - s->out1 = out1; - s->codepoint = codepoint; - s->rangeStart = kRegexInvalidRange; - return stateCount_++; - } - - void PushOperand(Stack& operandStack, unsigned codepoint) { - SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint); - *operandStack.template Push() = Frag(s, s, s); - } - - void ImplicitConcatenation(Stack& atomCountStack, Stack& operatorStack) { - if (*atomCountStack.template Top()) - *operatorStack.template Push() = kConcatenation; - (*atomCountStack.template Top())++; - } - - SizeType Append(SizeType l1, SizeType l2) { - SizeType old = l1; - while (GetState(l1).out != kRegexInvalidState) - l1 = GetState(l1).out; - GetState(l1).out = l2; - return old; - } - - void Patch(SizeType l, SizeType s) { - for (SizeType next; l != kRegexInvalidState; l = next) { - next = GetState(l).out; - GetState(l).out = s; - } - } - - bool Eval(Stack& operandStack, Operator op) { - switch (op) { - case kConcatenation: - RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2); - { - Frag e2 = *operandStack.template Pop(1); - Frag e1 = *operandStack.template Pop(1); - Patch(e1.out, e2.start); - *operandStack.template Push() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex)); - } - return true; - - case kAlternation: - if (operandStack.GetSize() >= sizeof(Frag) * 2) { - Frag e2 = *operandStack.template Pop(1); - Frag e1 = *operandStack.template Pop(1); - SizeType s = NewState(e1.start, e2.start, 0); - *operandStack.template Push() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex)); - return true; - } - return false; - - case kZeroOrOne: - if (operandStack.GetSize() >= sizeof(Frag)) { - Frag e = *operandStack.template Pop(1); - SizeType s = NewState(kRegexInvalidState, e.start, 0); - *operandStack.template Push() = Frag(s, Append(e.out, s), e.minIndex); - return true; - } - return false; - - case kZeroOrMore: - if (operandStack.GetSize() >= sizeof(Frag)) { - Frag e = *operandStack.template Pop(1); - SizeType s = NewState(kRegexInvalidState, e.start, 0); - Patch(e.out, s); - *operandStack.template Push() = Frag(s, s, e.minIndex); - return true; - } - return false; - - default: - RAPIDJSON_ASSERT(op == kOneOrMore); - if (operandStack.GetSize() >= sizeof(Frag)) { - Frag e = *operandStack.template Pop(1); - SizeType s = NewState(kRegexInvalidState, e.start, 0); - Patch(e.out, s); - *operandStack.template Push() = Frag(e.start, s, e.minIndex); - return true; - } - return false; - } - } - - bool EvalQuantifier(Stack& operandStack, unsigned n, unsigned m) { - RAPIDJSON_ASSERT(n <= m); - RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag)); - - if (n == 0) { - if (m == 0) // a{0} not support - return false; - else if (m == kInfinityQuantifier) - Eval(operandStack, kZeroOrMore); // a{0,} -> a* - else { - Eval(operandStack, kZeroOrOne); // a{0,5} -> a? - for (unsigned i = 0; i < m - 1; i++) - CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a? - for (unsigned i = 0; i < m - 1; i++) - Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a? - } - return true; - } - - for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a - CloneTopOperand(operandStack); - - if (m == kInfinityQuantifier) - Eval(operandStack, kOneOrMore); // a{3,} -> a a a+ - else if (m > n) { - CloneTopOperand(operandStack); // a{3,5} -> a a a a - Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a? - for (unsigned i = n; i < m - 1; i++) - CloneTopOperand(operandStack); // a{3,5} -> a a a a? a? - for (unsigned i = n; i < m; i++) - Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a? - } - - for (unsigned i = 0; i < n - 1; i++) - Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a? - - return true; - } - - static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; } - - void CloneTopOperand(Stack& operandStack) { - const Frag src = *operandStack.template Top(); // Copy constructor to prevent invalidation - SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_) - State* s = states_.template Push(count); - memcpy(s, &GetState(src.minIndex), count * sizeof(State)); - for (SizeType j = 0; j < count; j++) { - if (s[j].out != kRegexInvalidState) - s[j].out += count; - if (s[j].out1 != kRegexInvalidState) - s[j].out1 += count; - } - *operandStack.template Push() = Frag(src.start + count, src.out + count, src.minIndex + count); - stateCount_ += count; - } - - template - bool ParseUnsigned(DecodedStream& ds, unsigned* u) { - unsigned r = 0; - if (ds.Peek() < '0' || ds.Peek() > '9') - return false; - while (ds.Peek() >= '0' && ds.Peek() <= '9') { - if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295 - return false; // overflow - r = r * 10 + (ds.Take() - '0'); - } - *u = r; - return true; - } - - template - bool ParseRange(DecodedStream& ds, SizeType* range) { - bool isBegin = true; - bool negate = false; - int step = 0; - SizeType start = kRegexInvalidRange; - SizeType current = kRegexInvalidRange; - unsigned codepoint; - while ((codepoint = ds.Take()) != 0) { - if (isBegin) { - isBegin = false; - if (codepoint == '^') { - negate = true; - continue; - } - } - - switch (codepoint) { - case ']': - if (start == kRegexInvalidRange) - return false; // Error: nothing inside [] - if (step == 2) { // Add trailing '-' - SizeType r = NewRange('-'); - RAPIDJSON_ASSERT(current != kRegexInvalidRange); - GetRange(current).next = r; - } - if (negate) - GetRange(start).start |= kRangeNegationFlag; - *range = start; - return true; - - case '\\': - if (ds.Peek() == 'b') { - ds.Take(); - codepoint = 0x0008; // Escape backspace character - } - else if (!CharacterEscape(ds, &codepoint)) - return false; - // fall through to default - - default: - switch (step) { - case 1: - if (codepoint == '-') { - step++; - break; - } - // fall through to step 0 for other characters - - case 0: - { - SizeType r = NewRange(codepoint); - if (current != kRegexInvalidRange) - GetRange(current).next = r; - if (start == kRegexInvalidRange) - start = r; - current = r; - } - step = 1; - break; - - default: - RAPIDJSON_ASSERT(step == 2); - GetRange(current).end = codepoint; - step = 0; - } - } - } - return false; - } - - SizeType NewRange(unsigned codepoint) { - Range* r = ranges_.template Push(); - r->start = r->end = codepoint; - r->next = kRegexInvalidRange; - return rangeCount_++; - } - - template - bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { - unsigned codepoint; - switch (codepoint = ds.Take()) { - case '^': - case '$': - case '|': - case '(': - case ')': - case '?': - case '*': - case '+': - case '.': - case '[': - case ']': - case '{': - case '}': - case '\\': - *escapedCodepoint = codepoint; return true; - case 'f': *escapedCodepoint = 0x000C; return true; - case 'n': *escapedCodepoint = 0x000A; return true; - case 'r': *escapedCodepoint = 0x000D; return true; - case 't': *escapedCodepoint = 0x0009; return true; - case 'v': *escapedCodepoint = 0x000B; return true; - default: - return false; // Unsupported escape character - } - } - - template - bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const { - RAPIDJSON_ASSERT(IsValid()); - DecodedStream ds(is); - - state0_.Clear(); - Stack *current = &state0_, *next = &state1_; - const size_t stateSetSize = GetStateSetSize(); - std::memset(stateSet_, 0, stateSetSize); - - bool matched = AddState(*current, root_); - unsigned codepoint; - while (!current->Empty() && (codepoint = ds.Take()) != 0) { - std::memset(stateSet_, 0, stateSetSize); - next->Clear(); - matched = false; - for (const SizeType* s = current->template Bottom(); s != current->template End(); ++s) { - const State& sr = GetState(*s); - if (sr.codepoint == codepoint || - sr.codepoint == kAnyCharacterClass || - (sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) - { - matched = AddState(*next, sr.out) || matched; - if (!anchorEnd && matched) - return true; - } - if (!anchorBegin) - AddState(*next, root_); - } - internal::Swap(current, next); - } - - return matched; - } - - size_t GetStateSetSize() const { - return (stateCount_ + 31) / 32 * 4; - } - - // Return whether the added states is a match state - bool AddState(Stack& l, SizeType index) const { - RAPIDJSON_ASSERT(index != kRegexInvalidState); - - const State& s = GetState(index); - if (s.out1 != kRegexInvalidState) { // Split - bool matched = AddState(l, s.out); - return AddState(l, s.out1) || matched; - } - else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) { - stateSet_[index >> 5] |= (1 << (index & 31)); - *l.template PushUnsafe() = index; - } - return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. - } - - bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { - bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0; - while (rangeIndex != kRegexInvalidRange) { - const Range& r = GetRange(rangeIndex); - if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end) - return yes; - rangeIndex = r.next; - } - return !yes; - } - - Stack states_; - Stack ranges_; - SizeType root_; - SizeType stateCount_; - SizeType rangeCount_; - - static const unsigned kInfinityQuantifier = ~0u; - - // For SearchWithAnchoring() - uint32_t* stateSet_; // allocated by states_.GetAllocator() - mutable Stack state0_; - mutable Stack state1_; - bool anchorBegin_; - bool anchorEnd_; -}; - -typedef GenericRegex > Regex; - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#ifdef _MSC_VER -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_INTERNAL_REGEX_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/internal/stack.h b/src/Native/libcryptonight/3rdparty/rapidjson/internal/stack.h deleted file mode 100644 index 022c9aab4..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/internal/stack.h +++ /dev/null @@ -1,230 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_STACK_H_ -#define RAPIDJSON_INTERNAL_STACK_H_ - -#include "../allocators.h" -#include "swap.h" - -#if defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(c++98-compat) -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -/////////////////////////////////////////////////////////////////////////////// -// Stack - -//! A type-unsafe stack for storing different types of data. -/*! \tparam Allocator Allocator for allocating stack memory. -*/ -template -class Stack { -public: - // Optimization note: Do not allocate memory for stack_ in constructor. - // Do it lazily when first Push() -> Expand() -> Resize(). - Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - Stack(Stack&& rhs) - : allocator_(rhs.allocator_), - ownAllocator_(rhs.ownAllocator_), - stack_(rhs.stack_), - stackTop_(rhs.stackTop_), - stackEnd_(rhs.stackEnd_), - initialCapacity_(rhs.initialCapacity_) - { - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.stack_ = 0; - rhs.stackTop_ = 0; - rhs.stackEnd_ = 0; - rhs.initialCapacity_ = 0; - } -#endif - - ~Stack() { - Destroy(); - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - Stack& operator=(Stack&& rhs) { - if (&rhs != this) - { - Destroy(); - - allocator_ = rhs.allocator_; - ownAllocator_ = rhs.ownAllocator_; - stack_ = rhs.stack_; - stackTop_ = rhs.stackTop_; - stackEnd_ = rhs.stackEnd_; - initialCapacity_ = rhs.initialCapacity_; - - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.stack_ = 0; - rhs.stackTop_ = 0; - rhs.stackEnd_ = 0; - rhs.initialCapacity_ = 0; - } - return *this; - } -#endif - - void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { - internal::Swap(allocator_, rhs.allocator_); - internal::Swap(ownAllocator_, rhs.ownAllocator_); - internal::Swap(stack_, rhs.stack_); - internal::Swap(stackTop_, rhs.stackTop_); - internal::Swap(stackEnd_, rhs.stackEnd_); - internal::Swap(initialCapacity_, rhs.initialCapacity_); - } - - void Clear() { stackTop_ = stack_; } - - void ShrinkToFit() { - if (Empty()) { - // If the stack is empty, completely deallocate the memory. - Allocator::Free(stack_); - stack_ = 0; - stackTop_ = 0; - stackEnd_ = 0; - } - else - Resize(GetSize()); - } - - // Optimization note: try to minimize the size of this function for force inline. - // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. - template - RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { - // Expand the stack if needed - if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) - Expand(count); - } - - template - RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { - Reserve(count); - return PushUnsafe(count); - } - - template - RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { - RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); - T* ret = reinterpret_cast(stackTop_); - stackTop_ += sizeof(T) * count; - return ret; - } - - template - T* Pop(size_t count) { - RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); - stackTop_ -= count * sizeof(T); - return reinterpret_cast(stackTop_); - } - - template - T* Top() { - RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); - return reinterpret_cast(stackTop_ - sizeof(T)); - } - - template - const T* Top() const { - RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); - return reinterpret_cast(stackTop_ - sizeof(T)); - } - - template - T* End() { return reinterpret_cast(stackTop_); } - - template - const T* End() const { return reinterpret_cast(stackTop_); } - - template - T* Bottom() { return reinterpret_cast(stack_); } - - template - const T* Bottom() const { return reinterpret_cast(stack_); } - - bool HasAllocator() const { - return allocator_ != 0; - } - - Allocator& GetAllocator() { - RAPIDJSON_ASSERT(allocator_); - return *allocator_; - } - - bool Empty() const { return stackTop_ == stack_; } - size_t GetSize() const { return static_cast(stackTop_ - stack_); } - size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } - -private: - template - void Expand(size_t count) { - // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. - size_t newCapacity; - if (stack_ == 0) { - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); - newCapacity = initialCapacity_; - } else { - newCapacity = GetCapacity(); - newCapacity += (newCapacity + 1) / 2; - } - size_t newSize = GetSize() + sizeof(T) * count; - if (newCapacity < newSize) - newCapacity = newSize; - - Resize(newCapacity); - } - - void Resize(size_t newCapacity) { - const size_t size = GetSize(); // Backup the current size - stack_ = static_cast(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); - stackTop_ = stack_ + size; - stackEnd_ = stack_ + newCapacity; - } - - void Destroy() { - Allocator::Free(stack_); - RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack - } - - // Prohibit copy constructor & assignment operator. - Stack(const Stack&); - Stack& operator=(const Stack&); - - Allocator* allocator_; - Allocator* ownAllocator_; - char *stack_; - char *stackTop_; - char *stackEnd_; - size_t initialCapacity_; -}; - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_STACK_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/internal/strfunc.h b/src/Native/libcryptonight/3rdparty/rapidjson/internal/strfunc.h deleted file mode 100644 index 2edfae526..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/internal/strfunc.h +++ /dev/null @@ -1,55 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ -#define RAPIDJSON_INTERNAL_STRFUNC_H_ - -#include "../stream.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -//! Custom strlen() which works on different character types. -/*! \tparam Ch Character type (e.g. char, wchar_t, short) - \param s Null-terminated input string. - \return Number of characters in the string. - \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. -*/ -template -inline SizeType StrLen(const Ch* s) { - const Ch* p = s; - while (*p) ++p; - return SizeType(p - s); -} - -//! Returns number of code points in a encoded string. -template -bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { - GenericStringStream is(s); - const typename Encoding::Ch* end = s + length; - SizeType count = 0; - while (is.src_ < end) { - unsigned codepoint; - if (!Encoding::Decode(is, &codepoint)) - return false; - count++; - } - *outCount = count; - return true; -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/internal/strtod.h b/src/Native/libcryptonight/3rdparty/rapidjson/internal/strtod.h deleted file mode 100644 index 289c413b0..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/internal/strtod.h +++ /dev/null @@ -1,269 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_STRTOD_ -#define RAPIDJSON_STRTOD_ - -#include "ieee754.h" -#include "biginteger.h" -#include "diyfp.h" -#include "pow10.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -inline double FastPath(double significand, int exp) { - if (exp < -308) - return 0.0; - else if (exp >= 0) - return significand * internal::Pow10(exp); - else - return significand / internal::Pow10(-exp); -} - -inline double StrtodNormalPrecision(double d, int p) { - if (p < -308) { - // Prevent expSum < -308, making Pow10(p) = 0 - d = FastPath(d, -308); - d = FastPath(d, p + 308); - } - else - d = FastPath(d, p); - return d; -} - -template -inline T Min3(T a, T b, T c) { - T m = a; - if (m > b) m = b; - if (m > c) m = c; - return m; -} - -inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { - const Double db(b); - const uint64_t bInt = db.IntegerSignificand(); - const int bExp = db.IntegerExponent(); - const int hExp = bExp - 1; - - int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; - - // Adjust for decimal exponent - if (dExp >= 0) { - dS_Exp2 += dExp; - dS_Exp5 += dExp; - } - else { - bS_Exp2 -= dExp; - bS_Exp5 -= dExp; - hS_Exp2 -= dExp; - hS_Exp5 -= dExp; - } - - // Adjust for binary exponent - if (bExp >= 0) - bS_Exp2 += bExp; - else { - dS_Exp2 -= bExp; - hS_Exp2 -= bExp; - } - - // Adjust for half ulp exponent - if (hExp >= 0) - hS_Exp2 += hExp; - else { - dS_Exp2 -= hExp; - bS_Exp2 -= hExp; - } - - // Remove common power of two factor from all three scaled values - int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); - dS_Exp2 -= common_Exp2; - bS_Exp2 -= common_Exp2; - hS_Exp2 -= common_Exp2; - - BigInteger dS = d; - dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); - - BigInteger bS(bInt); - bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); - - BigInteger hS(1); - hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); - - BigInteger delta(0); - dS.Difference(bS, &delta); - - return delta.Compare(hS); -} - -inline bool StrtodFast(double d, int p, double* result) { - // Use fast path for string-to-double conversion if possible - // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ - if (p > 22 && p < 22 + 16) { - // Fast Path Cases In Disguise - d *= internal::Pow10(p - 22); - p = 22; - } - - if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 - *result = FastPath(d, p); - return true; - } - else - return false; -} - -// Compute an approximation and see if it is within 1/2 ULP -inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { - uint64_t significand = 0; - size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 - for (; i < length; i++) { - if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || - (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) - break; - significand = significand * 10u + static_cast(decimals[i] - '0'); - } - - if (i < length && decimals[i] >= '5') // Rounding - significand++; - - size_t remaining = length - i; - const unsigned kUlpShift = 3; - const unsigned kUlp = 1 << kUlpShift; - int64_t error = (remaining == 0) ? 0 : kUlp / 2; - - DiyFp v(significand, 0); - v = v.Normalize(); - error <<= -v.e; - - const int dExp = static_cast(decimalPosition) - static_cast(i) + exp; - - int actualExp; - DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); - if (actualExp != dExp) { - static const DiyFp kPow10[] = { - DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 - DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 - DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 - DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4 - DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5 - DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 - DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 - }; - int adjustment = dExp - actualExp - 1; - RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); - v = v * kPow10[adjustment]; - if (length + static_cast(adjustment)> 19u) // has more digits than decimal digits in 64-bit - error += kUlp / 2; - } - - v = v * cachedPower; - - error += kUlp + (error == 0 ? 0 : 1); - - const int oldExp = v.e; - v = v.Normalize(); - error <<= oldExp - v.e; - - const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); - unsigned precisionSize = 64 - effectiveSignificandSize; - if (precisionSize + kUlpShift >= 64) { - unsigned scaleExp = (precisionSize + kUlpShift) - 63; - v.f >>= scaleExp; - v.e += scaleExp; - error = (error >> scaleExp) + 1 + static_cast(kUlp); - precisionSize -= scaleExp; - } - - DiyFp rounded(v.f >> precisionSize, v.e + static_cast(precisionSize)); - const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; - const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; - if (precisionBits >= halfWay + static_cast(error)) { - rounded.f++; - if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) - rounded.f >>= 1; - rounded.e++; - } - } - - *result = rounded.ToDouble(); - - return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); -} - -inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { - const BigInteger dInt(decimals, length); - const int dExp = static_cast(decimalPosition) - static_cast(length) + exp; - Double a(approx); - int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); - if (cmp < 0) - return a.Value(); // within half ULP - else if (cmp == 0) { - // Round towards even - if (a.Significand() & 1) - return a.NextPositiveDouble(); - else - return a.Value(); - } - else // adjustment - return a.NextPositiveDouble(); -} - -inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { - RAPIDJSON_ASSERT(d >= 0.0); - RAPIDJSON_ASSERT(length >= 1); - - double result; - if (StrtodFast(d, p, &result)) - return result; - - // Trim leading zeros - while (*decimals == '0' && length > 1) { - length--; - decimals++; - decimalPosition--; - } - - // Trim trailing zeros - while (decimals[length - 1] == '0' && length > 1) { - length--; - decimalPosition--; - exp++; - } - - // Trim right-most digits - const int kMaxDecimalDigit = 780; - if (static_cast(length) > kMaxDecimalDigit) { - int delta = (static_cast(length) - kMaxDecimalDigit); - exp += delta; - decimalPosition -= static_cast(delta); - length = kMaxDecimalDigit; - } - - // If too small, underflow to zero - if (int(length) + exp < -324) - return 0.0; - - if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) - return result; - - // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison - return StrtodBigInteger(result, decimals, length, decimalPosition, exp); -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_STRTOD_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/internal/swap.h b/src/Native/libcryptonight/3rdparty/rapidjson/internal/swap.h deleted file mode 100644 index 666e49f97..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/internal/swap.h +++ /dev/null @@ -1,46 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_SWAP_H_ -#define RAPIDJSON_INTERNAL_SWAP_H_ - -#include "../rapidjson.h" - -#if defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(c++98-compat) -#endif - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -//! Custom swap() to avoid dependency on C++ header -/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. - \note This has the same semantics as std::swap(). -*/ -template -inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { - T tmp = a; - a = b; - b = tmp; -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_INTERNAL_SWAP_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/istreamwrapper.h b/src/Native/libcryptonight/3rdparty/rapidjson/istreamwrapper.h deleted file mode 100644 index f5fe28977..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/istreamwrapper.h +++ /dev/null @@ -1,115 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ISTREAMWRAPPER_H_ -#define RAPIDJSON_ISTREAMWRAPPER_H_ - -#include "stream.h" -#include - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -#ifdef _MSC_VER -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. -/*! - The classes can be wrapped including but not limited to: - - - \c std::istringstream - - \c std::stringstream - - \c std::wistringstream - - \c std::wstringstream - - \c std::ifstream - - \c std::fstream - - \c std::wifstream - - \c std::wfstream - - \tparam StreamType Class derived from \c std::basic_istream. -*/ - -template -class BasicIStreamWrapper { -public: - typedef typename StreamType::char_type Ch; - BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} - - Ch Peek() const { - typename StreamType::int_type c = stream_.peek(); - return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : '\0'; - } - - Ch Take() { - typename StreamType::int_type c = stream_.get(); - if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { - count_++; - return static_cast(c); - } - else - return '\0'; - } - - // tellg() may return -1 when failed. So we count by ourself. - size_t Tell() const { return count_; } - - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - - // For encoding detection only. - const Ch* Peek4() const { - RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. - int i; - bool hasError = false; - for (i = 0; i < 4; ++i) { - typename StreamType::int_type c = stream_.get(); - if (c == StreamType::traits_type::eof()) { - hasError = true; - stream_.clear(); - break; - } - peekBuffer_[i] = static_cast(c); - } - for (--i; i >= 0; --i) - stream_.putback(peekBuffer_[i]); - return !hasError ? peekBuffer_ : 0; - } - -private: - BasicIStreamWrapper(const BasicIStreamWrapper&); - BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); - - StreamType& stream_; - size_t count_; //!< Number of characters read. Note: - mutable Ch peekBuffer_[4]; -}; - -typedef BasicIStreamWrapper IStreamWrapper; -typedef BasicIStreamWrapper WIStreamWrapper; - -#if defined(__clang__) || defined(_MSC_VER) -RAPIDJSON_DIAG_POP -#endif - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_ISTREAMWRAPPER_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/memorybuffer.h b/src/Native/libcryptonight/3rdparty/rapidjson/memorybuffer.h deleted file mode 100644 index 39bee1dec..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/memorybuffer.h +++ /dev/null @@ -1,70 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_MEMORYBUFFER_H_ -#define RAPIDJSON_MEMORYBUFFER_H_ - -#include "stream.h" -#include "internal/stack.h" - -RAPIDJSON_NAMESPACE_BEGIN - -//! Represents an in-memory output byte stream. -/*! - This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. - - It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. - - Differences between MemoryBuffer and StringBuffer: - 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. - 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. - - \tparam Allocator type for allocating memory buffer. - \note implements Stream concept -*/ -template -struct GenericMemoryBuffer { - typedef char Ch; // byte - - GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} - - void Put(Ch c) { *stack_.template Push() = c; } - void Flush() {} - - void Clear() { stack_.Clear(); } - void ShrinkToFit() { stack_.ShrinkToFit(); } - Ch* Push(size_t count) { return stack_.template Push(count); } - void Pop(size_t count) { stack_.template Pop(count); } - - const Ch* GetBuffer() const { - return stack_.template Bottom(); - } - - size_t GetSize() const { return stack_.GetSize(); } - - static const size_t kDefaultCapacity = 256; - mutable internal::Stack stack_; -}; - -typedef GenericMemoryBuffer<> MemoryBuffer; - -//! Implement specialized version of PutN() with memset() for better performance. -template<> -inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { - std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); -} - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/memorystream.h b/src/Native/libcryptonight/3rdparty/rapidjson/memorystream.h deleted file mode 100644 index 1d71d8a4f..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/memorystream.h +++ /dev/null @@ -1,71 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_MEMORYSTREAM_H_ -#define RAPIDJSON_MEMORYSTREAM_H_ - -#include "stream.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(unreachable-code) -RAPIDJSON_DIAG_OFF(missing-noreturn) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Represents an in-memory input byte stream. -/*! - This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. - - It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. - - Differences between MemoryStream and StringStream: - 1. StringStream has encoding but MemoryStream is a byte stream. - 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. - 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). - \note implements Stream concept -*/ -struct MemoryStream { - typedef char Ch; // byte - - MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} - - Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } - Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } - size_t Tell() const { return static_cast(src_ - begin_); } - - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - - // For encoding detection only. - const Ch* Peek4() const { - return Tell() + 4 <= size_ ? src_ : 0; - } - - const Ch* src_; //!< Current read position. - const Ch* begin_; //!< Original head of the string. - const Ch* end_; //!< End of stream. - size_t size_; //!< Size of the stream. -}; - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/msinttypes/inttypes.h b/src/Native/libcryptonight/3rdparty/rapidjson/msinttypes/inttypes.h deleted file mode 100644 index 18111286b..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/msinttypes/inttypes.h +++ /dev/null @@ -1,316 +0,0 @@ -// ISO C9x compliant inttypes.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006-2013 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the product nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -// The above software in this distribution may have been modified by -// THL A29 Limited ("Tencent Modifications"). -// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_INTTYPES_H_ // [ -#define _MSC_INTTYPES_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include "stdint.h" - -// miloyip: VC supports inttypes.h since VC2013 -#if _MSC_VER >= 1800 -#include -#else - -// 7.8 Format conversion of integer types - -typedef struct { - intmax_t quot; - intmax_t rem; -} imaxdiv_t; - -// 7.8.1 Macros for format specifiers - -#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 - -// The fprintf macros for signed integers are: -#define PRId8 "d" -#define PRIi8 "i" -#define PRIdLEAST8 "d" -#define PRIiLEAST8 "i" -#define PRIdFAST8 "d" -#define PRIiFAST8 "i" - -#define PRId16 "hd" -#define PRIi16 "hi" -#define PRIdLEAST16 "hd" -#define PRIiLEAST16 "hi" -#define PRIdFAST16 "hd" -#define PRIiFAST16 "hi" - -#define PRId32 "I32d" -#define PRIi32 "I32i" -#define PRIdLEAST32 "I32d" -#define PRIiLEAST32 "I32i" -#define PRIdFAST32 "I32d" -#define PRIiFAST32 "I32i" - -#define PRId64 "I64d" -#define PRIi64 "I64i" -#define PRIdLEAST64 "I64d" -#define PRIiLEAST64 "I64i" -#define PRIdFAST64 "I64d" -#define PRIiFAST64 "I64i" - -#define PRIdMAX "I64d" -#define PRIiMAX "I64i" - -#define PRIdPTR "Id" -#define PRIiPTR "Ii" - -// The fprintf macros for unsigned integers are: -#define PRIo8 "o" -#define PRIu8 "u" -#define PRIx8 "x" -#define PRIX8 "X" -#define PRIoLEAST8 "o" -#define PRIuLEAST8 "u" -#define PRIxLEAST8 "x" -#define PRIXLEAST8 "X" -#define PRIoFAST8 "o" -#define PRIuFAST8 "u" -#define PRIxFAST8 "x" -#define PRIXFAST8 "X" - -#define PRIo16 "ho" -#define PRIu16 "hu" -#define PRIx16 "hx" -#define PRIX16 "hX" -#define PRIoLEAST16 "ho" -#define PRIuLEAST16 "hu" -#define PRIxLEAST16 "hx" -#define PRIXLEAST16 "hX" -#define PRIoFAST16 "ho" -#define PRIuFAST16 "hu" -#define PRIxFAST16 "hx" -#define PRIXFAST16 "hX" - -#define PRIo32 "I32o" -#define PRIu32 "I32u" -#define PRIx32 "I32x" -#define PRIX32 "I32X" -#define PRIoLEAST32 "I32o" -#define PRIuLEAST32 "I32u" -#define PRIxLEAST32 "I32x" -#define PRIXLEAST32 "I32X" -#define PRIoFAST32 "I32o" -#define PRIuFAST32 "I32u" -#define PRIxFAST32 "I32x" -#define PRIXFAST32 "I32X" - -#define PRIo64 "I64o" -#define PRIu64 "I64u" -#define PRIx64 "I64x" -#define PRIX64 "I64X" -#define PRIoLEAST64 "I64o" -#define PRIuLEAST64 "I64u" -#define PRIxLEAST64 "I64x" -#define PRIXLEAST64 "I64X" -#define PRIoFAST64 "I64o" -#define PRIuFAST64 "I64u" -#define PRIxFAST64 "I64x" -#define PRIXFAST64 "I64X" - -#define PRIoMAX "I64o" -#define PRIuMAX "I64u" -#define PRIxMAX "I64x" -#define PRIXMAX "I64X" - -#define PRIoPTR "Io" -#define PRIuPTR "Iu" -#define PRIxPTR "Ix" -#define PRIXPTR "IX" - -// The fscanf macros for signed integers are: -#define SCNd8 "d" -#define SCNi8 "i" -#define SCNdLEAST8 "d" -#define SCNiLEAST8 "i" -#define SCNdFAST8 "d" -#define SCNiFAST8 "i" - -#define SCNd16 "hd" -#define SCNi16 "hi" -#define SCNdLEAST16 "hd" -#define SCNiLEAST16 "hi" -#define SCNdFAST16 "hd" -#define SCNiFAST16 "hi" - -#define SCNd32 "ld" -#define SCNi32 "li" -#define SCNdLEAST32 "ld" -#define SCNiLEAST32 "li" -#define SCNdFAST32 "ld" -#define SCNiFAST32 "li" - -#define SCNd64 "I64d" -#define SCNi64 "I64i" -#define SCNdLEAST64 "I64d" -#define SCNiLEAST64 "I64i" -#define SCNdFAST64 "I64d" -#define SCNiFAST64 "I64i" - -#define SCNdMAX "I64d" -#define SCNiMAX "I64i" - -#ifdef _WIN64 // [ -# define SCNdPTR "I64d" -# define SCNiPTR "I64i" -#else // _WIN64 ][ -# define SCNdPTR "ld" -# define SCNiPTR "li" -#endif // _WIN64 ] - -// The fscanf macros for unsigned integers are: -#define SCNo8 "o" -#define SCNu8 "u" -#define SCNx8 "x" -#define SCNX8 "X" -#define SCNoLEAST8 "o" -#define SCNuLEAST8 "u" -#define SCNxLEAST8 "x" -#define SCNXLEAST8 "X" -#define SCNoFAST8 "o" -#define SCNuFAST8 "u" -#define SCNxFAST8 "x" -#define SCNXFAST8 "X" - -#define SCNo16 "ho" -#define SCNu16 "hu" -#define SCNx16 "hx" -#define SCNX16 "hX" -#define SCNoLEAST16 "ho" -#define SCNuLEAST16 "hu" -#define SCNxLEAST16 "hx" -#define SCNXLEAST16 "hX" -#define SCNoFAST16 "ho" -#define SCNuFAST16 "hu" -#define SCNxFAST16 "hx" -#define SCNXFAST16 "hX" - -#define SCNo32 "lo" -#define SCNu32 "lu" -#define SCNx32 "lx" -#define SCNX32 "lX" -#define SCNoLEAST32 "lo" -#define SCNuLEAST32 "lu" -#define SCNxLEAST32 "lx" -#define SCNXLEAST32 "lX" -#define SCNoFAST32 "lo" -#define SCNuFAST32 "lu" -#define SCNxFAST32 "lx" -#define SCNXFAST32 "lX" - -#define SCNo64 "I64o" -#define SCNu64 "I64u" -#define SCNx64 "I64x" -#define SCNX64 "I64X" -#define SCNoLEAST64 "I64o" -#define SCNuLEAST64 "I64u" -#define SCNxLEAST64 "I64x" -#define SCNXLEAST64 "I64X" -#define SCNoFAST64 "I64o" -#define SCNuFAST64 "I64u" -#define SCNxFAST64 "I64x" -#define SCNXFAST64 "I64X" - -#define SCNoMAX "I64o" -#define SCNuMAX "I64u" -#define SCNxMAX "I64x" -#define SCNXMAX "I64X" - -#ifdef _WIN64 // [ -# define SCNoPTR "I64o" -# define SCNuPTR "I64u" -# define SCNxPTR "I64x" -# define SCNXPTR "I64X" -#else // _WIN64 ][ -# define SCNoPTR "lo" -# define SCNuPTR "lu" -# define SCNxPTR "lx" -# define SCNXPTR "lX" -#endif // _WIN64 ] - -#endif // __STDC_FORMAT_MACROS ] - -// 7.8.2 Functions for greatest-width integer types - -// 7.8.2.1 The imaxabs function -#define imaxabs _abs64 - -// 7.8.2.2 The imaxdiv function - -// This is modified version of div() function from Microsoft's div.c found -// in %MSVC.NET%\crt\src\div.c -#ifdef STATIC_IMAXDIV // [ -static -#else // STATIC_IMAXDIV ][ -_inline -#endif // STATIC_IMAXDIV ] -imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) -{ - imaxdiv_t result; - - result.quot = numer / denom; - result.rem = numer % denom; - - if (numer < 0 && result.rem > 0) { - // did division wrong; must fix up - ++result.quot; - result.rem -= denom; - } - - return result; -} - -// 7.8.2.3 The strtoimax and strtoumax functions -#define strtoimax _strtoi64 -#define strtoumax _strtoui64 - -// 7.8.2.4 The wcstoimax and wcstoumax functions -#define wcstoimax _wcstoi64 -#define wcstoumax _wcstoui64 - -#endif // _MSC_VER >= 1800 - -#endif // _MSC_INTTYPES_H_ ] diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/msinttypes/stdint.h b/src/Native/libcryptonight/3rdparty/rapidjson/msinttypes/stdint.h deleted file mode 100644 index 3d4477b9a..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/msinttypes/stdint.h +++ /dev/null @@ -1,300 +0,0 @@ -// ISO C9x compliant stdint.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006-2013 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the product nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -// The above software in this distribution may have been modified by -// THL A29 Limited ("Tencent Modifications"). -// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_STDINT_H_ // [ -#define _MSC_STDINT_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010. -#if _MSC_VER >= 1600 // [ -#include - -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 - -#undef INT8_C -#undef INT16_C -#undef INT32_C -#undef INT64_C -#undef UINT8_C -#undef UINT16_C -#undef UINT32_C -#undef UINT64_C - -// 7.18.4.1 Macros for minimum-width integer constants - -#define INT8_C(val) val##i8 -#define INT16_C(val) val##i16 -#define INT32_C(val) val##i32 -#define INT64_C(val) val##i64 - -#define UINT8_C(val) val##ui8 -#define UINT16_C(val) val##ui16 -#define UINT32_C(val) val##ui32 -#define UINT64_C(val) val##ui64 - -// 7.18.4.2 Macros for greatest-width integer constants -// These #ifndef's are needed to prevent collisions with . -// Check out Issue 9 for the details. -#ifndef INTMAX_C // [ -# define INTMAX_C INT64_C -#endif // INTMAX_C ] -#ifndef UINTMAX_C // [ -# define UINTMAX_C UINT64_C -#endif // UINTMAX_C ] - -#endif // __STDC_CONSTANT_MACROS ] - -#else // ] _MSC_VER >= 1700 [ - -#include - -// For Visual Studio 6 in C++ mode and for many Visual Studio versions when -// compiling for ARM we have to wrap include with 'extern "C++" {}' -// or compiler would give many errors like this: -// error C2733: second C linkage of overloaded function 'wmemchr' not allowed -#if defined(__cplusplus) && !defined(_M_ARM) -extern "C" { -#endif -# include -#if defined(__cplusplus) && !defined(_M_ARM) -} -#endif - -// Define _W64 macros to mark types changing their size, like intptr_t. -#ifndef _W64 -# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 -# define _W64 __w64 -# else -# define _W64 -# endif -#endif - - -// 7.18.1 Integer types - -// 7.18.1.1 Exact-width integer types - -// Visual Studio 6 and Embedded Visual C++ 4 doesn't -// realize that, e.g. char has the same size as __int8 -// so we give up on __intX for them. -#if (_MSC_VER < 1300) - typedef signed char int8_t; - typedef signed short int16_t; - typedef signed int int32_t; - typedef unsigned char uint8_t; - typedef unsigned short uint16_t; - typedef unsigned int uint32_t; -#else - typedef signed __int8 int8_t; - typedef signed __int16 int16_t; - typedef signed __int32 int32_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; -#endif -typedef signed __int64 int64_t; -typedef unsigned __int64 uint64_t; - - -// 7.18.1.2 Minimum-width integer types -typedef int8_t int_least8_t; -typedef int16_t int_least16_t; -typedef int32_t int_least32_t; -typedef int64_t int_least64_t; -typedef uint8_t uint_least8_t; -typedef uint16_t uint_least16_t; -typedef uint32_t uint_least32_t; -typedef uint64_t uint_least64_t; - -// 7.18.1.3 Fastest minimum-width integer types -typedef int8_t int_fast8_t; -typedef int16_t int_fast16_t; -typedef int32_t int_fast32_t; -typedef int64_t int_fast64_t; -typedef uint8_t uint_fast8_t; -typedef uint16_t uint_fast16_t; -typedef uint32_t uint_fast32_t; -typedef uint64_t uint_fast64_t; - -// 7.18.1.4 Integer types capable of holding object pointers -#ifdef _WIN64 // [ - typedef signed __int64 intptr_t; - typedef unsigned __int64 uintptr_t; -#else // _WIN64 ][ - typedef _W64 signed int intptr_t; - typedef _W64 unsigned int uintptr_t; -#endif // _WIN64 ] - -// 7.18.1.5 Greatest-width integer types -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; - - -// 7.18.2 Limits of specified-width integer types - -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 - -// 7.18.2.1 Limits of exact-width integer types -#define INT8_MIN ((int8_t)_I8_MIN) -#define INT8_MAX _I8_MAX -#define INT16_MIN ((int16_t)_I16_MIN) -#define INT16_MAX _I16_MAX -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX _I32_MAX -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX _I64_MAX -#define UINT8_MAX _UI8_MAX -#define UINT16_MAX _UI16_MAX -#define UINT32_MAX _UI32_MAX -#define UINT64_MAX _UI64_MAX - -// 7.18.2.2 Limits of minimum-width integer types -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MIN INT64_MIN -#define INT_LEAST64_MAX INT64_MAX -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -// 7.18.2.3 Limits of fastest minimum-width integer types -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MIN INT64_MIN -#define INT_FAST64_MAX INT64_MAX -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -// 7.18.2.4 Limits of integer types capable of holding object pointers -#ifdef _WIN64 // [ -# define INTPTR_MIN INT64_MIN -# define INTPTR_MAX INT64_MAX -# define UINTPTR_MAX UINT64_MAX -#else // _WIN64 ][ -# define INTPTR_MIN INT32_MIN -# define INTPTR_MAX INT32_MAX -# define UINTPTR_MAX UINT32_MAX -#endif // _WIN64 ] - -// 7.18.2.5 Limits of greatest-width integer types -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -// 7.18.3 Limits of other integer types - -#ifdef _WIN64 // [ -# define PTRDIFF_MIN _I64_MIN -# define PTRDIFF_MAX _I64_MAX -#else // _WIN64 ][ -# define PTRDIFF_MIN _I32_MIN -# define PTRDIFF_MAX _I32_MAX -#endif // _WIN64 ] - -#define SIG_ATOMIC_MIN INT_MIN -#define SIG_ATOMIC_MAX INT_MAX - -#ifndef SIZE_MAX // [ -# ifdef _WIN64 // [ -# define SIZE_MAX _UI64_MAX -# else // _WIN64 ][ -# define SIZE_MAX _UI32_MAX -# endif // _WIN64 ] -#endif // SIZE_MAX ] - -// WCHAR_MIN and WCHAR_MAX are also defined in -#ifndef WCHAR_MIN // [ -# define WCHAR_MIN 0 -#endif // WCHAR_MIN ] -#ifndef WCHAR_MAX // [ -# define WCHAR_MAX _UI16_MAX -#endif // WCHAR_MAX ] - -#define WINT_MIN 0 -#define WINT_MAX _UI16_MAX - -#endif // __STDC_LIMIT_MACROS ] - - -// 7.18.4 Limits of other integer types - -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 - -// 7.18.4.1 Macros for minimum-width integer constants - -#define INT8_C(val) val##i8 -#define INT16_C(val) val##i16 -#define INT32_C(val) val##i32 -#define INT64_C(val) val##i64 - -#define UINT8_C(val) val##ui8 -#define UINT16_C(val) val##ui16 -#define UINT32_C(val) val##ui32 -#define UINT64_C(val) val##ui64 - -// 7.18.4.2 Macros for greatest-width integer constants -// These #ifndef's are needed to prevent collisions with . -// Check out Issue 9 for the details. -#ifndef INTMAX_C // [ -# define INTMAX_C INT64_C -#endif // INTMAX_C ] -#ifndef UINTMAX_C // [ -# define UINTMAX_C UINT64_C -#endif // UINTMAX_C ] - -#endif // __STDC_CONSTANT_MACROS ] - -#endif // _MSC_VER >= 1600 ] - -#endif // _MSC_STDINT_H_ ] diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/ostreamwrapper.h b/src/Native/libcryptonight/3rdparty/rapidjson/ostreamwrapper.h deleted file mode 100644 index 6f4667c08..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/ostreamwrapper.h +++ /dev/null @@ -1,81 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_OSTREAMWRAPPER_H_ -#define RAPIDJSON_OSTREAMWRAPPER_H_ - -#include "stream.h" -#include - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. -/*! - The classes can be wrapped including but not limited to: - - - \c std::ostringstream - - \c std::stringstream - - \c std::wpstringstream - - \c std::wstringstream - - \c std::ifstream - - \c std::fstream - - \c std::wofstream - - \c std::wfstream - - \tparam StreamType Class derived from \c std::basic_ostream. -*/ - -template -class BasicOStreamWrapper { -public: - typedef typename StreamType::char_type Ch; - BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} - - void Put(Ch c) { - stream_.put(c); - } - - void Flush() { - stream_.flush(); - } - - // Not implemented - char Peek() const { RAPIDJSON_ASSERT(false); return 0; } - char Take() { RAPIDJSON_ASSERT(false); return 0; } - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } - -private: - BasicOStreamWrapper(const BasicOStreamWrapper&); - BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); - - StreamType& stream_; -}; - -typedef BasicOStreamWrapper OStreamWrapper; -typedef BasicOStreamWrapper WOStreamWrapper; - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_OSTREAMWRAPPER_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/pointer.h b/src/Native/libcryptonight/3rdparty/rapidjson/pointer.h deleted file mode 100644 index 0206ac1c8..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/pointer.h +++ /dev/null @@ -1,1358 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_POINTER_H_ -#define RAPIDJSON_POINTER_H_ - -#include "document.h" -#include "internal/itoa.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(switch-enum) -#endif - -#ifdef _MSC_VER -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token - -//! Error code of parsing. -/*! \ingroup RAPIDJSON_ERRORS - \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode -*/ -enum PointerParseErrorCode { - kPointerParseErrorNone = 0, //!< The parse is successful - - kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' - kPointerParseErrorInvalidEscape, //!< Invalid escape - kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment - kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment -}; - -/////////////////////////////////////////////////////////////////////////////// -// GenericPointer - -//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator. -/*! - This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer" - (https://tools.ietf.org/html/rfc6901). - - A JSON pointer is for identifying a specific value in a JSON document - (GenericDocument). It can simplify coding of DOM tree manipulation, because it - can access multiple-level depth of DOM tree with single API call. - - After it parses a string representation (e.g. "/foo/0" or URI fragment - representation (e.g. "#/foo/0") into its internal representation (tokens), - it can be used to resolve a specific value in multiple documents, or sub-tree - of documents. - - Contrary to GenericValue, Pointer can be copy constructed and copy assigned. - Apart from assignment, a Pointer cannot be modified after construction. - - Although Pointer is very convenient, please aware that constructing Pointer - involves parsing and dynamic memory allocation. A special constructor with user- - supplied tokens eliminates these. - - GenericPointer depends on GenericDocument and GenericValue. - - \tparam ValueType The value type of the DOM tree. E.g. GenericValue > - \tparam Allocator The allocator type for allocating memory for internal representation. - - \note GenericPointer uses same encoding of ValueType. - However, Allocator of GenericPointer is independent of Allocator of Value. -*/ -template -class GenericPointer { -public: - typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value - typedef typename ValueType::Ch Ch; //!< Character type from Value - - //! A token is the basic units of internal representation. - /*! - A JSON pointer string representation "/foo/123" is parsed to two tokens: - "foo" and 123. 123 will be represented in both numeric form and string form. - They are resolved according to the actual value type (object or array). - - For token that are not numbers, or the numeric value is out of bound - (greater than limits of SizeType), they are only treated as string form - (i.e. the token's index will be equal to kPointerInvalidIndex). - - This struct is public so that user can create a Pointer without parsing and - allocation, using a special constructor. - */ - struct Token { - const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character. - SizeType length; //!< Length of the name. - SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex. - }; - - //!@name Constructors and destructor. - //@{ - - //! Default constructor. - GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} - - //! Constructor that parses a string or URI fragment representation. - /*! - \param source A null-terminated, string or URI fragment representation of JSON pointer. - \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. - */ - explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { - Parse(source, internal::StrLen(source)); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Constructor that parses a string or URI fragment representation. - /*! - \param source A string or URI fragment representation of JSON pointer. - \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. - \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. - */ - explicit GenericPointer(const std::basic_string& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { - Parse(source.c_str(), source.size()); - } -#endif - - //! Constructor that parses a string or URI fragment representation, with length of the source string. - /*! - \param source A string or URI fragment representation of JSON pointer. - \param length Length of source. - \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. - \note Slightly faster than the overload without length. - */ - GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { - Parse(source, length); - } - - //! Constructor with user-supplied tokens. - /*! - This constructor let user supplies const array of tokens. - This prevents the parsing process and eliminates allocation. - This is preferred for memory constrained environments. - - \param tokens An constant array of tokens representing the JSON pointer. - \param tokenCount Number of tokens. - - \b Example - \code - #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } - #define INDEX(i) { #i, sizeof(#i) - 1, i } - - static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) }; - static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); - // Equivalent to static const Pointer p("/foo/123"); - - #undef NAME - #undef INDEX - \endcode - */ - GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} - - //! Copy constructor. - GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { - *this = rhs; - } - - //! Destructor. - ~GenericPointer() { - if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. - Allocator::Free(tokens_); - RAPIDJSON_DELETE(ownAllocator_); - } - - //! Assignment operator. - GenericPointer& operator=(const GenericPointer& rhs) { - if (this != &rhs) { - // Do not delete ownAllcator - if (nameBuffer_) - Allocator::Free(tokens_); - - tokenCount_ = rhs.tokenCount_; - parseErrorOffset_ = rhs.parseErrorOffset_; - parseErrorCode_ = rhs.parseErrorCode_; - - if (rhs.nameBuffer_) - CopyFromRaw(rhs); // Normally parsed tokens. - else { - tokens_ = rhs.tokens_; // User supplied const tokens. - nameBuffer_ = 0; - } - } - return *this; - } - - //@} - - //!@name Append token - //@{ - - //! Append a token and return a new Pointer - /*! - \param token Token to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(const Token& token, Allocator* allocator = 0) const { - GenericPointer r; - r.allocator_ = allocator; - Ch *p = r.CopyFromRaw(*this, 1, token.length + 1); - std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch)); - r.tokens_[tokenCount_].name = p; - r.tokens_[tokenCount_].length = token.length; - r.tokens_[tokenCount_].index = token.index; - return r; - } - - //! Append a name token with length, and return a new Pointer - /*! - \param name Name to be appended. - \param length Length of name. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const { - Token token = { name, length, kPointerInvalidIndex }; - return Append(token, allocator); - } - - //! Append a name token without length, and return a new Pointer - /*! - \param name Name (const Ch*) to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) - Append(T* name, Allocator* allocator = 0) const { - return Append(name, StrLen(name), allocator); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Append a name token, and return a new Pointer - /*! - \param name Name to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(const std::basic_string& name, Allocator* allocator = 0) const { - return Append(name.c_str(), static_cast(name.size()), allocator); - } -#endif - - //! Append a index token, and return a new Pointer - /*! - \param index Index to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(SizeType index, Allocator* allocator = 0) const { - char buffer[21]; - char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer); - SizeType length = static_cast(end - buffer); - buffer[length] = '\0'; - - if (sizeof(Ch) == 1) { - Token token = { reinterpret_cast(buffer), length, index }; - return Append(token, allocator); - } - else { - Ch name[21]; - for (size_t i = 0; i <= length; i++) - name[i] = buffer[i]; - Token token = { name, length, index }; - return Append(token, allocator); - } - } - - //! Append a token by value, and return a new Pointer - /*! - \param token token to be appended. - \param allocator Allocator for the newly return Pointer. - \return A new Pointer with appended token. - */ - GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const { - if (token.IsString()) - return Append(token.GetString(), token.GetStringLength(), allocator); - else { - RAPIDJSON_ASSERT(token.IsUint64()); - RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); - return Append(static_cast(token.GetUint64()), allocator); - } - } - - //!@name Handling Parse Error - //@{ - - //! Check whether this is a valid pointer. - bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; } - - //! Get the parsing error offset in code unit. - size_t GetParseErrorOffset() const { return parseErrorOffset_; } - - //! Get the parsing error code. - PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; } - - //@} - - //! Get the allocator of this pointer. - Allocator& GetAllocator() { return *allocator_; } - - //!@name Tokens - //@{ - - //! Get the token array (const version only). - const Token* GetTokens() const { return tokens_; } - - //! Get the number of tokens. - size_t GetTokenCount() const { return tokenCount_; } - - //@} - - //!@name Equality/inequality operators - //@{ - - //! Equality operator. - /*! - \note When any pointers are invalid, always returns false. - */ - bool operator==(const GenericPointer& rhs) const { - if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_) - return false; - - for (size_t i = 0; i < tokenCount_; i++) { - if (tokens_[i].index != rhs.tokens_[i].index || - tokens_[i].length != rhs.tokens_[i].length || - (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0)) - { - return false; - } - } - - return true; - } - - //! Inequality operator. - /*! - \note When any pointers are invalid, always returns true. - */ - bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); } - - //@} - - //!@name Stringify - //@{ - - //! Stringify the pointer into string representation. - /*! - \tparam OutputStream Type of output stream. - \param os The output stream. - */ - template - bool Stringify(OutputStream& os) const { - return Stringify(os); - } - - //! Stringify the pointer into URI fragment representation. - /*! - \tparam OutputStream Type of output stream. - \param os The output stream. - */ - template - bool StringifyUriFragment(OutputStream& os) const { - return Stringify(os); - } - - //@} - - //!@name Create value - //@{ - - //! Create a value in a subtree. - /*! - If the value is not exist, it creates all parent values and a JSON Null value. - So it always succeed and return the newly created or existing value. - - Remind that it may change types of parents according to tokens, so it - potentially removes previously stored values. For example, if a document - was an array, and "/foo" is used to create a value, then the document - will be changed to an object, and all existing array elements are lost. - - \param root Root value of a DOM subtree to be resolved. It can be any value other than document root. - \param allocator Allocator for creating the values if the specified value or its parents are not exist. - \param alreadyExist If non-null, it stores whether the resolved value is already exist. - \return The resolved newly created (a JSON Null value), or already exists value. - */ - ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const { - RAPIDJSON_ASSERT(IsValid()); - ValueType* v = &root; - bool exist = true; - for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { - if (v->IsArray() && t->name[0] == '-' && t->length == 1) { - v->PushBack(ValueType().Move(), allocator); - v = &((*v)[v->Size() - 1]); - exist = false; - } - else { - if (t->index == kPointerInvalidIndex) { // must be object name - if (!v->IsObject()) - v->SetObject(); // Change to Object - } - else { // object name or array index - if (!v->IsArray() && !v->IsObject()) - v->SetArray(); // Change to Array - } - - if (v->IsArray()) { - if (t->index >= v->Size()) { - v->Reserve(t->index + 1, allocator); - while (t->index >= v->Size()) - v->PushBack(ValueType().Move(), allocator); - exist = false; - } - v = &((*v)[t->index]); - } - else { - typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); - if (m == v->MemberEnd()) { - v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); - v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end - exist = false; - } - else - v = &m->value; - } - } - } - - if (alreadyExist) - *alreadyExist = exist; - - return *v; - } - - //! Creates a value in a document. - /*! - \param document A document to be resolved. - \param alreadyExist If non-null, it stores whether the resolved value is already exist. - \return The resolved newly created, or already exists value. - */ - template - ValueType& Create(GenericDocument& document, bool* alreadyExist = 0) const { - return Create(document, document.GetAllocator(), alreadyExist); - } - - //@} - - //!@name Query value - //@{ - - //! Query a value in a subtree. - /*! - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. - \return Pointer to the value if it can be resolved. Otherwise null. - - \note - There are only 3 situations when a value cannot be resolved: - 1. A value in the path is not an array nor object. - 2. An object value does not contain the token. - 3. A token is out of range of an array value. - - Use unresolvedTokenIndex to retrieve the token index. - */ - ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const { - RAPIDJSON_ASSERT(IsValid()); - ValueType* v = &root; - for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { - switch (v->GetType()) { - case kObjectType: - { - typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); - if (m == v->MemberEnd()) - break; - v = &m->value; - } - continue; - case kArrayType: - if (t->index == kPointerInvalidIndex || t->index >= v->Size()) - break; - v = &((*v)[t->index]); - continue; - default: - break; - } - - // Error: unresolved token - if (unresolvedTokenIndex) - *unresolvedTokenIndex = static_cast(t - tokens_); - return 0; - } - return v; - } - - //! Query a const value in a const subtree. - /*! - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \return Pointer to the value if it can be resolved. Otherwise null. - */ - const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { - return Get(const_cast(root), unresolvedTokenIndex); - } - - //@} - - //!@name Query a value with default - //@{ - - //! Query a value in a subtree with default value. - /*! - Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value. - So that this function always succeed. - - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \param defaultValue Default value to be cloned if the value was not exists. - \param allocator Allocator for creating the values if the specified value or its parents are not exist. - \see Create() - */ - ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { - bool alreadyExist; - Value& v = Create(root, allocator, &alreadyExist); - return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); - } - - //! Query a value in a subtree with default null-terminated string. - ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const { - bool alreadyExist; - Value& v = Create(root, allocator, &alreadyExist); - return alreadyExist ? v : v.SetString(defaultValue, allocator); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Query a value in a subtree with default std::basic_string. - ValueType& GetWithDefault(ValueType& root, const std::basic_string& defaultValue, typename ValueType::AllocatorType& allocator) const { - bool alreadyExist; - Value& v = Create(root, allocator, &alreadyExist); - return alreadyExist ? v : v.SetString(defaultValue, allocator); - } -#endif - - //! Query a value in a subtree with default primitive value. - /*! - \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) - GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const { - return GetWithDefault(root, ValueType(defaultValue).Move(), allocator); - } - - //! Query a value in a document with default value. - template - ValueType& GetWithDefault(GenericDocument& document, const ValueType& defaultValue) const { - return GetWithDefault(document, defaultValue, document.GetAllocator()); - } - - //! Query a value in a document with default null-terminated string. - template - ValueType& GetWithDefault(GenericDocument& document, const Ch* defaultValue) const { - return GetWithDefault(document, defaultValue, document.GetAllocator()); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Query a value in a document with default std::basic_string. - template - ValueType& GetWithDefault(GenericDocument& document, const std::basic_string& defaultValue) const { - return GetWithDefault(document, defaultValue, document.GetAllocator()); - } -#endif - - //! Query a value in a document with default primitive value. - /*! - \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) - GetWithDefault(GenericDocument& document, T defaultValue) const { - return GetWithDefault(document, defaultValue, document.GetAllocator()); - } - - //@} - - //!@name Set a value - //@{ - - //! Set a value in a subtree, with move semantics. - /*! - It creates all parents if they are not exist or types are different to the tokens. - So this function always succeeds but potentially remove existing values. - - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \param value Value to be set. - \param allocator Allocator for creating the values if the specified value or its parents are not exist. - \see Create() - */ - ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator) = value; - } - - //! Set a value in a subtree, with copy semantics. - ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator).CopyFrom(value, allocator); - } - - //! Set a null-terminated string in a subtree. - ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator) = ValueType(value, allocator).Move(); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Set a std::basic_string in a subtree. - ValueType& Set(ValueType& root, const std::basic_string& value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator) = ValueType(value, allocator).Move(); - } -#endif - - //! Set a primitive value in a subtree. - /*! - \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) - Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator) = ValueType(value).Move(); - } - - //! Set a value in a document, with move semantics. - template - ValueType& Set(GenericDocument& document, ValueType& value) const { - return Create(document) = value; - } - - //! Set a value in a document, with copy semantics. - template - ValueType& Set(GenericDocument& document, const ValueType& value) const { - return Create(document).CopyFrom(value, document.GetAllocator()); - } - - //! Set a null-terminated string in a document. - template - ValueType& Set(GenericDocument& document, const Ch* value) const { - return Create(document) = ValueType(value, document.GetAllocator()).Move(); - } - -#if RAPIDJSON_HAS_STDSTRING - //! Sets a std::basic_string in a document. - template - ValueType& Set(GenericDocument& document, const std::basic_string& value) const { - return Create(document) = ValueType(value, document.GetAllocator()).Move(); - } -#endif - - //! Set a primitive value in a document. - /*! - \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool - */ - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) - Set(GenericDocument& document, T value) const { - return Create(document) = value; - } - - //@} - - //!@name Swap a value - //@{ - - //! Swap a value with a value in a subtree. - /*! - It creates all parents if they are not exist or types are different to the tokens. - So this function always succeeds but potentially remove existing values. - - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \param value Value to be swapped. - \param allocator Allocator for creating the values if the specified value or its parents are not exist. - \see Create() - */ - ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { - return Create(root, allocator).Swap(value); - } - - //! Swap a value with a value in a document. - template - ValueType& Swap(GenericDocument& document, ValueType& value) const { - return Create(document).Swap(value); - } - - //@} - - //! Erase a value in a subtree. - /*! - \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. - \return Whether the resolved value is found and erased. - - \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false. - */ - bool Erase(ValueType& root) const { - RAPIDJSON_ASSERT(IsValid()); - if (tokenCount_ == 0) // Cannot erase the root - return false; - - ValueType* v = &root; - const Token* last = tokens_ + (tokenCount_ - 1); - for (const Token *t = tokens_; t != last; ++t) { - switch (v->GetType()) { - case kObjectType: - { - typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); - if (m == v->MemberEnd()) - return false; - v = &m->value; - } - break; - case kArrayType: - if (t->index == kPointerInvalidIndex || t->index >= v->Size()) - return false; - v = &((*v)[t->index]); - break; - default: - return false; - } - } - - switch (v->GetType()) { - case kObjectType: - return v->EraseMember(GenericStringRef(last->name, last->length)); - case kArrayType: - if (last->index == kPointerInvalidIndex || last->index >= v->Size()) - return false; - v->Erase(v->Begin() + last->index); - return true; - default: - return false; - } - } - -private: - //! Clone the content from rhs to this. - /*! - \param rhs Source pointer. - \param extraToken Extra tokens to be allocated. - \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated. - \return Start of non-occupied name buffer, for storing extra names. - */ - Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { - if (!allocator_) // allocator is independently owned. - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); - - size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens - for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) - nameBufferSize += t->length; - - tokenCount_ = rhs.tokenCount_ + extraToken; - tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); - nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); - if (rhs.tokenCount_ > 0) { - std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); - } - if (nameBufferSize > 0) { - std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); - } - - // Adjust pointers to name buffer - std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; - for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) - t->name += diff; - - return nameBuffer_ + nameBufferSize; - } - - //! Check whether a character should be percent-encoded. - /*! - According to RFC 3986 2.3 Unreserved Characters. - \param c The character (code unit) to be tested. - */ - bool NeedPercentEncode(Ch c) const { - return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~'); - } - - //! Parse a JSON String or its URI fragment representation into tokens. -#ifndef __clang__ // -Wdocumentation - /*! - \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. - \param length Length of the source string. - \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. - */ -#endif - void Parse(const Ch* source, size_t length) { - RAPIDJSON_ASSERT(source != NULL); - RAPIDJSON_ASSERT(nameBuffer_ == 0); - RAPIDJSON_ASSERT(tokens_ == 0); - - // Create own allocator if user did not supply. - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); - - // Count number of '/' as tokenCount - tokenCount_ = 0; - for (const Ch* s = source; s != source + length; s++) - if (*s == '/') - tokenCount_++; - - Token* token = tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch))); - Ch* name = nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); - size_t i = 0; - - // Detect if it is a URI fragment - bool uriFragment = false; - if (source[i] == '#') { - uriFragment = true; - i++; - } - - if (i != length && source[i] != '/') { - parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus; - goto error; - } - - while (i < length) { - RAPIDJSON_ASSERT(source[i] == '/'); - i++; // consumes '/' - - token->name = name; - bool isNumber = true; - - while (i < length && source[i] != '/') { - Ch c = source[i]; - if (uriFragment) { - // Decoding percent-encoding for URI fragment - if (c == '%') { - PercentDecodeStream is(&source[i], source + length); - GenericInsituStringStream os(name); - Ch* begin = os.PutBegin(); - if (!Transcoder, EncodingType>().Validate(is, os) || !is.IsValid()) { - parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding; - goto error; - } - size_t len = os.PutEnd(begin); - i += is.Tell() - 1; - if (len == 1) - c = *name; - else { - name += len; - isNumber = false; - i++; - continue; - } - } - else if (NeedPercentEncode(c)) { - parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode; - goto error; - } - } - - i++; - - // Escaping "~0" -> '~', "~1" -> '/' - if (c == '~') { - if (i < length) { - c = source[i]; - if (c == '0') c = '~'; - else if (c == '1') c = '/'; - else { - parseErrorCode_ = kPointerParseErrorInvalidEscape; - goto error; - } - i++; - } - else { - parseErrorCode_ = kPointerParseErrorInvalidEscape; - goto error; - } - } - - // First check for index: all of characters are digit - if (c < '0' || c > '9') - isNumber = false; - - *name++ = c; - } - token->length = static_cast(name - token->name); - if (token->length == 0) - isNumber = false; - *name++ = '\0'; // Null terminator - - // Second check for index: more than one digit cannot have leading zero - if (isNumber && token->length > 1 && token->name[0] == '0') - isNumber = false; - - // String to SizeType conversion - SizeType n = 0; - if (isNumber) { - for (size_t j = 0; j < token->length; j++) { - SizeType m = n * 10 + static_cast(token->name[j] - '0'); - if (m < n) { // overflow detection - isNumber = false; - break; - } - n = m; - } - } - - token->index = isNumber ? n : kPointerInvalidIndex; - token++; - } - - RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer - parseErrorCode_ = kPointerParseErrorNone; - return; - - error: - Allocator::Free(tokens_); - nameBuffer_ = 0; - tokens_ = 0; - tokenCount_ = 0; - parseErrorOffset_ = i; - return; - } - - //! Stringify to string or URI fragment representation. - /*! - \tparam uriFragment True for stringifying to URI fragment representation. False for string representation. - \tparam OutputStream type of output stream. - \param os The output stream. - */ - template - bool Stringify(OutputStream& os) const { - RAPIDJSON_ASSERT(IsValid()); - - if (uriFragment) - os.Put('#'); - - for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { - os.Put('/'); - for (size_t j = 0; j < t->length; j++) { - Ch c = t->name[j]; - if (c == '~') { - os.Put('~'); - os.Put('0'); - } - else if (c == '/') { - os.Put('~'); - os.Put('1'); - } - else if (uriFragment && NeedPercentEncode(c)) { - // Transcode to UTF8 sequence - GenericStringStream source(&t->name[j]); - PercentEncodeStream target(os); - if (!Transcoder >().Validate(source, target)) - return false; - j += source.Tell() - 1; - } - else - os.Put(c); - } - } - return true; - } - - //! A helper stream for decoding a percent-encoded sequence into code unit. - /*! - This stream decodes %XY triplet into code unit (0-255). - If it encounters invalid characters, it sets output code unit as 0 and - mark invalid, and to be checked by IsValid(). - */ - class PercentDecodeStream { - public: - typedef typename ValueType::Ch Ch; - - //! Constructor - /*! - \param source Start of the stream - \param end Past-the-end of the stream. - */ - PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {} - - Ch Take() { - if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet - valid_ = false; - return 0; - } - src_++; - Ch c = 0; - for (int j = 0; j < 2; j++) { - c = static_cast(c << 4); - Ch h = *src_; - if (h >= '0' && h <= '9') c = static_cast(c + h - '0'); - else if (h >= 'A' && h <= 'F') c = static_cast(c + h - 'A' + 10); - else if (h >= 'a' && h <= 'f') c = static_cast(c + h - 'a' + 10); - else { - valid_ = false; - return 0; - } - src_++; - } - return c; - } - - size_t Tell() const { return static_cast(src_ - head_); } - bool IsValid() const { return valid_; } - - private: - const Ch* src_; //!< Current read position. - const Ch* head_; //!< Original head of the string. - const Ch* end_; //!< Past-the-end position. - bool valid_; //!< Whether the parsing is valid. - }; - - //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence. - template - class PercentEncodeStream { - public: - PercentEncodeStream(OutputStream& os) : os_(os) {} - void Put(char c) { // UTF-8 must be byte - unsigned char u = static_cast(c); - static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - os_.Put('%'); - os_.Put(hexDigits[u >> 4]); - os_.Put(hexDigits[u & 15]); - } - private: - OutputStream& os_; - }; - - Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. - Allocator* ownAllocator_; //!< Allocator owned by this Pointer. - Ch* nameBuffer_; //!< A buffer containing all names in tokens. - Token* tokens_; //!< A list of tokens. - size_t tokenCount_; //!< Number of tokens in tokens_. - size_t parseErrorOffset_; //!< Offset in code unit when parsing fail. - PointerParseErrorCode parseErrorCode_; //!< Parsing error code. -}; - -//! GenericPointer for Value (UTF-8, default allocator). -typedef GenericPointer Pointer; - -//!@name Helper functions for GenericPointer -//@{ - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer& pointer, typename T::AllocatorType& a) { - return pointer.Create(root, a); -} - -template -typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Create(root, a); -} - -// No allocator parameter - -template -typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer& pointer) { - return pointer.Create(document); -} - -template -typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) { - return GenericPointer(source, N - 1).Create(document); -} - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType* GetValueByPointer(T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { - return pointer.Get(root, unresolvedTokenIndex); -} - -template -const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { - return pointer.Get(root, unresolvedTokenIndex); -} - -template -typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) { - return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); -} - -template -const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) { - return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); -} - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { - return pointer.GetWithDefault(root, defaultValue, a); -} - -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) { - return pointer.GetWithDefault(root, defaultValue, a); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const std::basic_string& defaultValue, typename T::AllocatorType& a) { - return pointer.GetWithDefault(root, defaultValue, a); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) -GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, T2 defaultValue, typename T::AllocatorType& a) { - return pointer.GetWithDefault(root, defaultValue, a); -} - -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); -} - -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string& defaultValue, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) -GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); -} - -// No allocator parameter - -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& defaultValue) { - return pointer.GetWithDefault(document, defaultValue); -} - -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* defaultValue) { - return pointer.GetWithDefault(document, defaultValue); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const std::basic_string& defaultValue) { - return pointer.GetWithDefault(document, defaultValue); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) -GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, T2 defaultValue) { - return pointer.GetWithDefault(document, defaultValue); -} - -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) { - return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); -} - -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) { - return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string& defaultValue) { - return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) -GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) { - return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); -} - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::Ch* value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const std::basic_string& value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) -SetValueByPointer(T& root, const GenericPointer& pointer, T2 value, typename T::AllocatorType& a) { - return pointer.Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} - -template -typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string& value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) -SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Set(root, value, a); -} - -// No allocator parameter - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { - return pointer.Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& value) { - return pointer.Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* value) { - return pointer.Set(document, value); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const std::basic_string& value) { - return pointer.Set(document, value); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) -SetValueByPointer(DocumentType& document, const GenericPointer& pointer, T2 value) { - return pointer.Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { - return GenericPointer(source, N - 1).Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) { - return GenericPointer(source, N - 1).Set(document, value); -} - -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) { - return GenericPointer(source, N - 1).Set(document, value); -} - -#if RAPIDJSON_HAS_STDSTRING -template -typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string& value) { - return GenericPointer(source, N - 1).Set(document, value); -} -#endif - -template -RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) -SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) { - return GenericPointer(source, N - 1).Set(document, value); -} - -////////////////////////////////////////////////////////////////////////////// - -template -typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { - return pointer.Swap(root, value, a); -} - -template -typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { - return GenericPointer(source, N - 1).Swap(root, value, a); -} - -template -typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { - return pointer.Swap(document, value); -} - -template -typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { - return GenericPointer(source, N - 1).Swap(document, value); -} - -////////////////////////////////////////////////////////////////////////////// - -template -bool EraseValueByPointer(T& root, const GenericPointer& pointer) { - return pointer.Erase(root); -} - -template -bool EraseValueByPointer(T& root, const CharType(&source)[N]) { - return GenericPointer(source, N - 1).Erase(root); -} - -//@} - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#ifdef _MSC_VER -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_POINTER_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/prettywriter.h b/src/Native/libcryptonight/3rdparty/rapidjson/prettywriter.h deleted file mode 100644 index 0dcb0fee9..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/prettywriter.h +++ /dev/null @@ -1,255 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_PRETTYWRITER_H_ -#define RAPIDJSON_PRETTYWRITER_H_ - -#include "writer.h" - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Combination of PrettyWriter format flags. -/*! \see PrettyWriter::SetFormatOptions - */ -enum PrettyFormatOptions { - kFormatDefault = 0, //!< Default pretty formatting. - kFormatSingleLineArray = 1 //!< Format arrays on a single line. -}; - -//! Writer with indentation and spacing. -/*! - \tparam OutputStream Type of ouptut os. - \tparam SourceEncoding Encoding of source string. - \tparam TargetEncoding Encoding of output stream. - \tparam StackAllocator Type of allocator for allocating memory of stack. -*/ -template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> -class PrettyWriter : public Writer { -public: - typedef Writer Base; - typedef typename Base::Ch Ch; - - //! Constructor - /*! \param os Output stream. - \param allocator User supplied allocator. If it is null, it will create a private one. - \param levelDepth Initial capacity of stack. - */ - explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : - Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} - - - explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : - Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} - - //! Set custom indentation. - /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). - \param indentCharCount Number of indent characters for each indentation level. - \note The default indentation is 4 spaces. - */ - PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { - RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); - indentChar_ = indentChar; - indentCharCount_ = indentCharCount; - return *this; - } - - //! Set pretty writer formatting options. - /*! \param options Formatting options. - */ - PrettyWriter& SetFormatOptions(PrettyFormatOptions options) { - formatOptions_ = options; - return *this; - } - - /*! @name Implementation of Handler - \see Handler - */ - //@{ - - bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); } - bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } - bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); } - bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); } - bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } - bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } - bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } - - bool RawNumber(const Ch* str, SizeType length, bool copy = false) { - (void)copy; - PrettyPrefix(kNumberType); - return Base::WriteString(str, length); - } - - bool String(const Ch* str, SizeType length, bool copy = false) { - (void)copy; - PrettyPrefix(kStringType); - return Base::WriteString(str, length); - } - -#if RAPIDJSON_HAS_STDSTRING - bool String(const std::basic_string& str) { - return String(str.data(), SizeType(str.size())); - } -#endif - - bool StartObject() { - PrettyPrefix(kObjectType); - new (Base::level_stack_.template Push()) typename Base::Level(false); - return Base::WriteStartObject(); - } - - bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } - -#if RAPIDJSON_HAS_STDSTRING - bool Key(const std::basic_string& str) { - return Key(str.data(), SizeType(str.size())); - } -#endif - - bool EndObject(SizeType memberCount = 0) { - (void)memberCount; - RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); - RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); - bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; - - if (!empty) { - Base::os_->Put('\n'); - WriteIndent(); - } - bool ret = Base::WriteEndObject(); - (void)ret; - RAPIDJSON_ASSERT(ret == true); - if (Base::level_stack_.Empty()) // end of json text - Base::os_->Flush(); - return true; - } - - bool StartArray() { - PrettyPrefix(kArrayType); - new (Base::level_stack_.template Push()) typename Base::Level(true); - return Base::WriteStartArray(); - } - - bool EndArray(SizeType memberCount = 0) { - (void)memberCount; - RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); - RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); - bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; - - if (!empty && !(formatOptions_ & kFormatSingleLineArray)) { - Base::os_->Put('\n'); - WriteIndent(); - } - bool ret = Base::WriteEndArray(); - (void)ret; - RAPIDJSON_ASSERT(ret == true); - if (Base::level_stack_.Empty()) // end of json text - Base::os_->Flush(); - return true; - } - - //@} - - /*! @name Convenience extensions */ - //@{ - - //! Simpler but slower overload. - bool String(const Ch* str) { return String(str, internal::StrLen(str)); } - bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } - - //@} - - //! Write a raw JSON value. - /*! - For user to write a stringified JSON as a value. - - \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. - \param length Length of the json. - \param type Type of the root of json. - \note When using PrettyWriter::RawValue(), the result json may not be indented correctly. - */ - bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); } - -protected: - void PrettyPrefix(Type type) { - (void)type; - if (Base::level_stack_.GetSize() != 0) { // this value is not at root - typename Base::Level* level = Base::level_stack_.template Top(); - - if (level->inArray) { - if (level->valueCount > 0) { - Base::os_->Put(','); // add comma if it is not the first element in array - if (formatOptions_ & kFormatSingleLineArray) - Base::os_->Put(' '); - } - - if (!(formatOptions_ & kFormatSingleLineArray)) { - Base::os_->Put('\n'); - WriteIndent(); - } - } - else { // in object - if (level->valueCount > 0) { - if (level->valueCount % 2 == 0) { - Base::os_->Put(','); - Base::os_->Put('\n'); - } - else { - Base::os_->Put(':'); - Base::os_->Put(' '); - } - } - else - Base::os_->Put('\n'); - - if (level->valueCount % 2 == 0) - WriteIndent(); - } - if (!level->inArray && level->valueCount % 2 == 0) - RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name - level->valueCount++; - } - else { - RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. - Base::hasRoot_ = true; - } - } - - void WriteIndent() { - size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; - PutN(*Base::os_, static_cast(indentChar_), count); - } - - Ch indentChar_; - unsigned indentCharCount_; - PrettyFormatOptions formatOptions_; - -private: - // Prohibit copy constructor & assignment operator. - PrettyWriter(const PrettyWriter&); - PrettyWriter& operator=(const PrettyWriter&); -}; - -RAPIDJSON_NAMESPACE_END - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/rapidjson.h b/src/Native/libcryptonight/3rdparty/rapidjson/rapidjson.h deleted file mode 100644 index 2ef9bc56c..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/rapidjson.h +++ /dev/null @@ -1,614 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_RAPIDJSON_H_ -#define RAPIDJSON_RAPIDJSON_H_ - -/*!\file rapidjson.h - \brief common definitions and configuration - - \see RAPIDJSON_CONFIG - */ - -/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration - \brief Configuration macros for library features - - Some RapidJSON features are configurable to adapt the library to a wide - variety of platforms, environments and usage scenarios. Most of the - features can be configured in terms of overriden or predefined - preprocessor macros at compile-time. - - Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs. - - \note These macros should be given on the compiler command-line - (where applicable) to avoid inconsistent values when compiling - different translation units of a single application. - */ - -#include // malloc(), realloc(), free(), size_t -#include // memset(), memcpy(), memmove(), memcmp() - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_VERSION_STRING -// -// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. -// - -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -// token stringification -#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) -#define RAPIDJSON_DO_STRINGIFY(x) #x -//!@endcond - -/*! \def RAPIDJSON_MAJOR_VERSION - \ingroup RAPIDJSON_CONFIG - \brief Major version of RapidJSON in integer. -*/ -/*! \def RAPIDJSON_MINOR_VERSION - \ingroup RAPIDJSON_CONFIG - \brief Minor version of RapidJSON in integer. -*/ -/*! \def RAPIDJSON_PATCH_VERSION - \ingroup RAPIDJSON_CONFIG - \brief Patch version of RapidJSON in integer. -*/ -/*! \def RAPIDJSON_VERSION_STRING - \ingroup RAPIDJSON_CONFIG - \brief Version of RapidJSON in ".." string format. -*/ -#define RAPIDJSON_MAJOR_VERSION 1 -#define RAPIDJSON_MINOR_VERSION 1 -#define RAPIDJSON_PATCH_VERSION 0 -#define RAPIDJSON_VERSION_STRING \ - RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_NAMESPACE_(BEGIN|END) -/*! \def RAPIDJSON_NAMESPACE - \ingroup RAPIDJSON_CONFIG - \brief provide custom rapidjson namespace - - In order to avoid symbol clashes and/or "One Definition Rule" errors - between multiple inclusions of (different versions of) RapidJSON in - a single binary, users can customize the name of the main RapidJSON - namespace. - - In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE - to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple - levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref - RAPIDJSON_NAMESPACE_END need to be defined as well: - - \code - // in some .cpp file - #define RAPIDJSON_NAMESPACE my::rapidjson - #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { - #define RAPIDJSON_NAMESPACE_END } } - #include "rapidjson/..." - \endcode - - \see rapidjson - */ -/*! \def RAPIDJSON_NAMESPACE_BEGIN - \ingroup RAPIDJSON_CONFIG - \brief provide custom rapidjson namespace (opening expression) - \see RAPIDJSON_NAMESPACE -*/ -/*! \def RAPIDJSON_NAMESPACE_END - \ingroup RAPIDJSON_CONFIG - \brief provide custom rapidjson namespace (closing expression) - \see RAPIDJSON_NAMESPACE -*/ -#ifndef RAPIDJSON_NAMESPACE -#define RAPIDJSON_NAMESPACE rapidjson -#endif -#ifndef RAPIDJSON_NAMESPACE_BEGIN -#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE { -#endif -#ifndef RAPIDJSON_NAMESPACE_END -#define RAPIDJSON_NAMESPACE_END } -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_HAS_STDSTRING - -#ifndef RAPIDJSON_HAS_STDSTRING -#ifdef RAPIDJSON_DOXYGEN_RUNNING -#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation -#else -#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default -#endif -/*! \def RAPIDJSON_HAS_STDSTRING - \ingroup RAPIDJSON_CONFIG - \brief Enable RapidJSON support for \c std::string - - By defining this preprocessor symbol to \c 1, several convenience functions for using - \ref rapidjson::GenericValue with \c std::string are enabled, especially - for construction and comparison. - - \hideinitializer -*/ -#endif // !defined(RAPIDJSON_HAS_STDSTRING) - -#if RAPIDJSON_HAS_STDSTRING -#include -#endif // RAPIDJSON_HAS_STDSTRING - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_NO_INT64DEFINE - -/*! \def RAPIDJSON_NO_INT64DEFINE - \ingroup RAPIDJSON_CONFIG - \brief Use external 64-bit integer types. - - RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types - to be available at global scope. - - If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to - prevent RapidJSON from defining its own types. -*/ -#ifndef RAPIDJSON_NO_INT64DEFINE -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 -#include "msinttypes/stdint.h" -#include "msinttypes/inttypes.h" -#else -// Other compilers should have this. -#include -#include -#endif -//!@endcond -#ifdef RAPIDJSON_DOXYGEN_RUNNING -#define RAPIDJSON_NO_INT64DEFINE -#endif -#endif // RAPIDJSON_NO_INT64TYPEDEF - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_FORCEINLINE - -#ifndef RAPIDJSON_FORCEINLINE -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#if defined(_MSC_VER) && defined(NDEBUG) -#define RAPIDJSON_FORCEINLINE __forceinline -#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG) -#define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) -#else -#define RAPIDJSON_FORCEINLINE -#endif -//!@endcond -#endif // RAPIDJSON_FORCEINLINE - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ENDIAN -#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine -#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine - -//! Endianness of the machine. -/*! - \def RAPIDJSON_ENDIAN - \ingroup RAPIDJSON_CONFIG - - GCC 4.6 provided macro for detecting endianness of the target machine. But other - compilers may not have this. User can define RAPIDJSON_ENDIAN to either - \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. - - Default detection implemented with reference to - \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html - \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp -*/ -#ifndef RAPIDJSON_ENDIAN -// Detect with GCC 4.6's macro -# ifdef __BYTE_ORDER__ -# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN -# else -# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. -# endif // __BYTE_ORDER__ -// Detect with GLIBC's endian.h -# elif defined(__GLIBC__) -# include -# if (__BYTE_ORDER == __LITTLE_ENDIAN) -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif (__BYTE_ORDER == __BIG_ENDIAN) -# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN -# else -# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. -# endif // __GLIBC__ -// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro -# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) -# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN -// Detect with architecture macros -# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) -# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN -# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif defined(_MSC_VER) && defined(_M_ARM) -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif defined(RAPIDJSON_DOXYGEN_RUNNING) -# define RAPIDJSON_ENDIAN -# else -# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. -# endif -#endif // RAPIDJSON_ENDIAN - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_64BIT - -//! Whether using 64-bit architecture -#ifndef RAPIDJSON_64BIT -#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__) -#define RAPIDJSON_64BIT 1 -#else -#define RAPIDJSON_64BIT 0 -#endif -#endif // RAPIDJSON_64BIT - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ALIGN - -//! Data alignment of the machine. -/*! \ingroup RAPIDJSON_CONFIG - \param x pointer to align - - Some machines require strict data alignment. Currently the default uses 4 bytes - alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms. - User can customize by defining the RAPIDJSON_ALIGN function macro. -*/ -#ifndef RAPIDJSON_ALIGN -#if RAPIDJSON_64BIT == 1 -#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) -#else -#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u) -#endif -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_UINT64_C2 - -//! Construct a 64-bit literal by a pair of 32-bit integer. -/*! - 64-bit literal with or without ULL suffix is prone to compiler warnings. - UINT64_C() is C macro which cause compilation problems. - Use this macro to define 64-bit constants by a pair of 32-bit integer. -*/ -#ifndef RAPIDJSON_UINT64_C2 -#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_48BITPOINTER_OPTIMIZATION - -//! Use only lower 48-bit address for some pointers. -/*! - \ingroup RAPIDJSON_CONFIG - - This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address. - The higher 16-bit can be used for storing other data. - \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture. -*/ -#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION -#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) -#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1 -#else -#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 -#endif -#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION - -#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1 -#if RAPIDJSON_64BIT != 1 -#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1 -#endif -#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast((reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast(reinterpret_cast(x)))) -#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast(reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF)))) -#else -#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) -#define RAPIDJSON_GETPOINTER(type, p) (p) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD - -/*! \def RAPIDJSON_SIMD - \ingroup RAPIDJSON_CONFIG - \brief Enable SSE2/SSE4.2 optimization. - - RapidJSON supports optimized implementations for some parsing operations - based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible - processors. - - To enable these optimizations, two different symbols can be defined; - \code - // Enable SSE2 optimization. - #define RAPIDJSON_SSE2 - - // Enable SSE4.2 optimization. - #define RAPIDJSON_SSE42 - \endcode - - \c RAPIDJSON_SSE42 takes precedence, if both are defined. - - If any of these symbols is defined, RapidJSON defines the macro - \c RAPIDJSON_SIMD to indicate the availability of the optimized code. -*/ -#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ - || defined(RAPIDJSON_DOXYGEN_RUNNING) -#define RAPIDJSON_SIMD -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_NO_SIZETYPEDEFINE - -#ifndef RAPIDJSON_NO_SIZETYPEDEFINE -/*! \def RAPIDJSON_NO_SIZETYPEDEFINE - \ingroup RAPIDJSON_CONFIG - \brief User-provided \c SizeType definition. - - In order to avoid using 32-bit size types for indexing strings and arrays, - define this preprocessor symbol and provide the type rapidjson::SizeType - before including RapidJSON: - \code - #define RAPIDJSON_NO_SIZETYPEDEFINE - namespace rapidjson { typedef ::std::size_t SizeType; } - #include "rapidjson/..." - \endcode - - \see rapidjson::SizeType -*/ -#ifdef RAPIDJSON_DOXYGEN_RUNNING -#define RAPIDJSON_NO_SIZETYPEDEFINE -#endif -RAPIDJSON_NAMESPACE_BEGIN -//! Size type (for string lengths, array sizes, etc.) -/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms, - instead of using \c size_t. Users may override the SizeType by defining - \ref RAPIDJSON_NO_SIZETYPEDEFINE. -*/ -typedef unsigned SizeType; -RAPIDJSON_NAMESPACE_END -#endif - -// always import std::size_t to rapidjson namespace -RAPIDJSON_NAMESPACE_BEGIN -using std::size_t; -RAPIDJSON_NAMESPACE_END - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ASSERT - -//! Assertion. -/*! \ingroup RAPIDJSON_CONFIG - By default, rapidjson uses C \c assert() for internal assertions. - User can override it by defining RAPIDJSON_ASSERT(x) macro. - - \note Parsing errors are handled and can be customized by the - \ref RAPIDJSON_ERRORS APIs. -*/ -#ifndef RAPIDJSON_ASSERT -#define RAPIDJSON_ASSERT(x) -#endif // RAPIDJSON_ASSERT - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_STATIC_ASSERT - -// Adopt from boost -#ifndef RAPIDJSON_STATIC_ASSERT -#ifndef __clang__ -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#endif -RAPIDJSON_NAMESPACE_BEGIN -template struct STATIC_ASSERTION_FAILURE; -template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; -template struct StaticAssertTest {}; -RAPIDJSON_NAMESPACE_END - -#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) -#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) -#define RAPIDJSON_DO_JOIN2(X, Y) X##Y - -#if defined(__GNUC__) -#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) -#else -#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE -#endif -#ifndef __clang__ -//!@endcond -#endif - -/*! \def RAPIDJSON_STATIC_ASSERT - \brief (Internal) macro to check for conditions at compile-time - \param x compile-time condition - \hideinitializer - */ -#define RAPIDJSON_STATIC_ASSERT(x) \ - typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ - sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ - RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY - -//! Compiler branching hint for expression with high probability to be true. -/*! - \ingroup RAPIDJSON_CONFIG - \param x Boolean expression likely to be true. -*/ -#ifndef RAPIDJSON_LIKELY -#if defined(__GNUC__) || defined(__clang__) -#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) -#else -#define RAPIDJSON_LIKELY(x) (x) -#endif -#endif - -//! Compiler branching hint for expression with low probability to be true. -/*! - \ingroup RAPIDJSON_CONFIG - \param x Boolean expression unlikely to be true. -*/ -#ifndef RAPIDJSON_UNLIKELY -#if defined(__GNUC__) || defined(__clang__) -#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) -#else -#define RAPIDJSON_UNLIKELY(x) (x) -#endif -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Helpers - -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN - -#define RAPIDJSON_MULTILINEMACRO_BEGIN do { -#define RAPIDJSON_MULTILINEMACRO_END \ -} while((void)0, 0) - -// adopted from Boost -#define RAPIDJSON_VERSION_CODE(x,y,z) \ - (((x)*100000) + ((y)*100) + (z)) - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF - -#if defined(__GNUC__) -#define RAPIDJSON_GNUC \ - RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) -#endif - -#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) - -#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) -#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) -#define RAPIDJSON_DIAG_OFF(x) \ - RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) - -// push/pop support in Clang and GCC>=4.6 -#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) -#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) -#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) -#else // GCC >= 4.2, < 4.6 -#define RAPIDJSON_DIAG_PUSH /* ignored */ -#define RAPIDJSON_DIAG_POP /* ignored */ -#endif - -#elif defined(_MSC_VER) - -// pragma (MSVC specific) -#define RAPIDJSON_PRAGMA(x) __pragma(x) -#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) - -#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x) -#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) -#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) - -#else - -#define RAPIDJSON_DIAG_OFF(x) /* ignored */ -#define RAPIDJSON_DIAG_PUSH /* ignored */ -#define RAPIDJSON_DIAG_POP /* ignored */ - -#endif // RAPIDJSON_DIAG_* - -/////////////////////////////////////////////////////////////////////////////// -// C++11 features - -#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS -#if defined(__clang__) -#if __has_feature(cxx_rvalue_references) && \ - (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 -#else -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 -#endif -#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1600) - -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 -#else -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 -#endif -#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - -#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT -#if defined(__clang__) -#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) -#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) -// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported -#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 -#else -#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 -#endif -#endif -#if RAPIDJSON_HAS_CXX11_NOEXCEPT -#define RAPIDJSON_NOEXCEPT noexcept -#else -#define RAPIDJSON_NOEXCEPT /* noexcept */ -#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT - -// no automatic detection, yet -#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS -#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 -#endif - -#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR -#if defined(__clang__) -#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) -#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1700) -#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 -#else -#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 -#endif -#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR - -//!@endcond - -/////////////////////////////////////////////////////////////////////////////// -// new/delete - -#ifndef RAPIDJSON_NEW -///! customization point for global \c new -#define RAPIDJSON_NEW(x) new x -#endif -#ifndef RAPIDJSON_DELETE -///! customization point for global \c delete -#define RAPIDJSON_DELETE(x) delete x -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Type - -/*! \namespace rapidjson - \brief main RapidJSON namespace - \see RAPIDJSON_NAMESPACE -*/ -RAPIDJSON_NAMESPACE_BEGIN - -//! Type of JSON value -enum Type { - kNullType = 0, //!< null - kFalseType = 1, //!< false - kTrueType = 2, //!< true - kObjectType = 3, //!< object - kArrayType = 4, //!< array - kStringType = 5, //!< string - kNumberType = 6 //!< number -}; - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/reader.h b/src/Native/libcryptonight/3rdparty/rapidjson/reader.h deleted file mode 100644 index 303aac2e3..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/reader.h +++ /dev/null @@ -1,1879 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_READER_H_ -#define RAPIDJSON_READER_H_ - -/*! \file reader.h */ - -#include "allocators.h" -#include "stream.h" -#include "encodedstream.h" -#include "internal/meta.h" -#include "internal/stack.h" -#include "internal/strtod.h" -#include - -#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) -#include -#pragma intrinsic(_BitScanForward) -#endif -#ifdef RAPIDJSON_SSE42 -#include -#elif defined(RAPIDJSON_SSE2) -#include -#endif - -#ifdef _MSC_VER -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -RAPIDJSON_DIAG_OFF(4702) // unreachable code -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(old-style-cast) -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(switch-enum) -#endif - -#ifdef __GNUC__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(effc++) -#endif - -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#define RAPIDJSON_NOTHING /* deliberately empty */ -#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN -#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ - RAPIDJSON_MULTILINEMACRO_BEGIN \ - if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \ - RAPIDJSON_MULTILINEMACRO_END -#endif -#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) -//!@endcond - -/*! \def RAPIDJSON_PARSE_ERROR_NORETURN - \ingroup RAPIDJSON_ERRORS - \brief Macro to indicate a parse error. - \param parseErrorCode \ref rapidjson::ParseErrorCode of the error - \param offset position of the error in JSON input (\c size_t) - - This macros can be used as a customization point for the internal - error handling mechanism of RapidJSON. - - A common usage model is to throw an exception instead of requiring the - caller to explicitly check the \ref rapidjson::GenericReader::Parse's - return value: - - \code - #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ - throw ParseException(parseErrorCode, #parseErrorCode, offset) - - #include // std::runtime_error - #include "rapidjson/error/error.h" // rapidjson::ParseResult - - struct ParseException : std::runtime_error, rapidjson::ParseResult { - ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset) - : std::runtime_error(msg), ParseResult(code, offset) {} - }; - - #include "rapidjson/reader.h" - \endcode - - \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse - */ -#ifndef RAPIDJSON_PARSE_ERROR_NORETURN -#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ - RAPIDJSON_MULTILINEMACRO_BEGIN \ - RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ - SetParseError(parseErrorCode, offset); \ - RAPIDJSON_MULTILINEMACRO_END -#endif - -/*! \def RAPIDJSON_PARSE_ERROR - \ingroup RAPIDJSON_ERRORS - \brief (Internal) macro to indicate and handle a parse error. - \param parseErrorCode \ref rapidjson::ParseErrorCode of the error - \param offset position of the error in JSON input (\c size_t) - - Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. - - \see RAPIDJSON_PARSE_ERROR_NORETURN - \hideinitializer - */ -#ifndef RAPIDJSON_PARSE_ERROR -#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ - RAPIDJSON_MULTILINEMACRO_BEGIN \ - RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ - RAPIDJSON_MULTILINEMACRO_END -#endif - -#include "error/error.h" // ParseErrorCode, ParseResult - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// ParseFlag - -/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS - \ingroup RAPIDJSON_CONFIG - \brief User-defined kParseDefaultFlags definition. - - User can define this as any \c ParseFlag combinations. -*/ -#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS -#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseCommentsFlag | kParseTrailingCommasFlag -#endif - -//! Combination of parseFlags -/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream - */ -enum ParseFlag { - kParseNoFlags = 0, //!< No flags are set. - kParseInsituFlag = 1, //!< In-situ(destructive) parsing. - kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. - kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. - kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. - kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). - kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments. - kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. - kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. - kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. - kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS -}; - -/////////////////////////////////////////////////////////////////////////////// -// Handler - -/*! \class rapidjson::Handler - \brief Concept for receiving events from GenericReader upon parsing. - The functions return true if no error occurs. If they return false, - the event publisher should terminate the process. -\code -concept Handler { - typename Ch; - - bool Null(); - bool Bool(bool b); - bool Int(int i); - bool Uint(unsigned i); - bool Int64(int64_t i); - bool Uint64(uint64_t i); - bool Double(double d); - /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) - bool RawNumber(const Ch* str, SizeType length, bool copy); - bool String(const Ch* str, SizeType length, bool copy); - bool StartObject(); - bool Key(const Ch* str, SizeType length, bool copy); - bool EndObject(SizeType memberCount); - bool StartArray(); - bool EndArray(SizeType elementCount); -}; -\endcode -*/ -/////////////////////////////////////////////////////////////////////////////// -// BaseReaderHandler - -//! Default implementation of Handler. -/*! This can be used as base class of any reader handler. - \note implements Handler concept -*/ -template, typename Derived = void> -struct BaseReaderHandler { - typedef typename Encoding::Ch Ch; - - typedef typename internal::SelectIf, BaseReaderHandler, Derived>::Type Override; - - bool Default() { return true; } - bool Null() { return static_cast(*this).Default(); } - bool Bool(bool) { return static_cast(*this).Default(); } - bool Int(int) { return static_cast(*this).Default(); } - bool Uint(unsigned) { return static_cast(*this).Default(); } - bool Int64(int64_t) { return static_cast(*this).Default(); } - bool Uint64(uint64_t) { return static_cast(*this).Default(); } - bool Double(double) { return static_cast(*this).Default(); } - /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) - bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } - bool String(const Ch*, SizeType, bool) { return static_cast(*this).Default(); } - bool StartObject() { return static_cast(*this).Default(); } - bool Key(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } - bool EndObject(SizeType) { return static_cast(*this).Default(); } - bool StartArray() { return static_cast(*this).Default(); } - bool EndArray(SizeType) { return static_cast(*this).Default(); } -}; - -/////////////////////////////////////////////////////////////////////////////// -// StreamLocalCopy - -namespace internal { - -template::copyOptimization> -class StreamLocalCopy; - -//! Do copy optimization. -template -class StreamLocalCopy { -public: - StreamLocalCopy(Stream& original) : s(original), original_(original) {} - ~StreamLocalCopy() { original_ = s; } - - Stream s; - -private: - StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; - - Stream& original_; -}; - -//! Keep reference. -template -class StreamLocalCopy { -public: - StreamLocalCopy(Stream& original) : s(original) {} - - Stream& s; - -private: - StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; -}; - -} // namespace internal - -/////////////////////////////////////////////////////////////////////////////// -// SkipWhitespace - -//! Skip the JSON white spaces in a stream. -/*! \param is A input stream for skipping white spaces. - \note This function has SSE2/SSE4.2 specialization. -*/ -template -void SkipWhitespace(InputStream& is) { - internal::StreamLocalCopy copy(is); - InputStream& s(copy.s); - - typename InputStream::Ch c; - while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t') - s.Take(); -} - -inline const char* SkipWhitespace(const char* p, const char* end) { - while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) - ++p; - return p; -} - -#ifdef RAPIDJSON_SSE42 -//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. -inline const char *SkipWhitespace_SIMD(const char* p) { - // Fast return for single non-whitespace - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - // 16-byte align to the next boundary - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - // The rest of string using SIMD - static const char whitespace[16] = " \n\r\t"; - const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); - - for (;; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); - if (r != 0) { // some of characters is non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return p + offset; -#else - return p + __builtin_ffs(r) - 1; -#endif - } - } -} - -inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { - // Fast return for single non-whitespace - if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) - ++p; - else - return p; - - // The middle of string using SIMD - static const char whitespace[16] = " \n\r\t"; - const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); - - for (; p <= end - 16; p += 16) { - const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); - const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); - if (r != 0) { // some of characters is non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return p + offset; -#else - return p + __builtin_ffs(r) - 1; -#endif - } - } - - return SkipWhitespace(p, end); -} - -#elif defined(RAPIDJSON_SSE2) - -//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. -inline const char *SkipWhitespace_SIMD(const char* p) { - // Fast return for single non-whitespace - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - // 16-byte align to the next boundary - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; - - // The rest of string - #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } - static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; - #undef C16 - - const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); - const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); - const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); - const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); - - for (;; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - __m128i x = _mm_cmpeq_epi8(s, w0); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); - unsigned short r = static_cast(~_mm_movemask_epi8(x)); - if (r != 0) { // some of characters may be non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return p + offset; -#else - return p + __builtin_ffs(r) - 1; -#endif - } - } -} - -inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { - // Fast return for single non-whitespace - if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) - ++p; - else - return p; - - // The rest of string - #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } - static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; - #undef C16 - - const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); - const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); - const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); - const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); - - for (; p <= end - 16; p += 16) { - const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); - __m128i x = _mm_cmpeq_epi8(s, w0); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); - unsigned short r = static_cast(~_mm_movemask_epi8(x)); - if (r != 0) { // some of characters may be non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return p + offset; -#else - return p + __builtin_ffs(r) - 1; -#endif - } - } - - return SkipWhitespace(p, end); -} - -#endif // RAPIDJSON_SSE2 - -#ifdef RAPIDJSON_SIMD -//! Template function specialization for InsituStringStream -template<> inline void SkipWhitespace(InsituStringStream& is) { - is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); -} - -//! Template function specialization for StringStream -template<> inline void SkipWhitespace(StringStream& is) { - is.src_ = SkipWhitespace_SIMD(is.src_); -} - -template<> inline void SkipWhitespace(EncodedInputStream, MemoryStream>& is) { - is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_); -} -#endif // RAPIDJSON_SIMD - -/////////////////////////////////////////////////////////////////////////////// -// GenericReader - -//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. -/*! GenericReader parses JSON text from a stream, and send events synchronously to an - object implementing Handler concept. - - It needs to allocate a stack for storing a single decoded string during - non-destructive parsing. - - For in-situ parsing, the decoded string is directly written to the source - text string, no temporary buffer is required. - - A GenericReader object can be reused for parsing multiple JSON text. - - \tparam SourceEncoding Encoding of the input stream. - \tparam TargetEncoding Encoding of the parse output. - \tparam StackAllocator Allocator type for stack. -*/ -template -class GenericReader { -public: - typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type - - //! Constructor. - /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) - \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) - */ - GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {} - - //! Parse JSON text. - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam InputStream Type of input stream, implementing Stream concept. - \tparam Handler Type of handler, implementing Handler concept. - \param is Input stream to be parsed. - \param handler The handler to receive events. - \return Whether the parsing is successful. - */ - template - ParseResult Parse(InputStream& is, Handler& handler) { - if (parseFlags & kParseIterativeFlag) - return IterativeParse(is, handler); - - parseResult_.Clear(); - - ClearStackOnExit scope(*this); - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - - if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - } - else { - ParseValue(is, handler); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - - if (!(parseFlags & kParseStopWhenDoneFlag)) { - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - - if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - } - } - } - - return parseResult_; - } - - //! Parse JSON text (with \ref kParseDefaultFlags) - /*! \tparam InputStream Type of input stream, implementing Stream concept - \tparam Handler Type of handler, implementing Handler concept. - \param is Input stream to be parsed. - \param handler The handler to receive events. - \return Whether the parsing is successful. - */ - template - ParseResult Parse(InputStream& is, Handler& handler) { - return Parse(is, handler); - } - - //! Whether a parse error has occured in the last parsing. - bool HasParseError() const { return parseResult_.IsError(); } - - //! Get the \ref ParseErrorCode of last parsing. - ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } - - //! Get the position of last parsing error in input, 0 otherwise. - size_t GetErrorOffset() const { return parseResult_.Offset(); } - -protected: - void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); } - -private: - // Prohibit copy constructor & assignment operator. - GenericReader(const GenericReader&); - GenericReader& operator=(const GenericReader&); - - void ClearStack() { stack_.Clear(); } - - // clear stack on any exit from ParseStream, e.g. due to exception - struct ClearStackOnExit { - explicit ClearStackOnExit(GenericReader& r) : r_(r) {} - ~ClearStackOnExit() { r_.ClearStack(); } - private: - GenericReader& r_; - ClearStackOnExit(const ClearStackOnExit&); - ClearStackOnExit& operator=(const ClearStackOnExit&); - }; - - template - void SkipWhitespaceAndComments(InputStream& is) { - SkipWhitespace(is); - - if (parseFlags & kParseCommentsFlag) { - while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) { - if (Consume(is, '*')) { - while (true) { - if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) - RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); - else if (Consume(is, '*')) { - if (Consume(is, '/')) - break; - } - else - is.Take(); - } - } - else if (RAPIDJSON_LIKELY(Consume(is, '/'))) - while (is.Peek() != '\0' && is.Take() != '\n'); - else - RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); - - SkipWhitespace(is); - } - } - } - - // Parse object: { string : value, ... } - template - void ParseObject(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == '{'); - is.Take(); // Skip '{' - - if (RAPIDJSON_UNLIKELY(!handler.StartObject())) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - if (Consume(is, '}')) { - if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - return; - } - - for (SizeType memberCount = 0;;) { - if (RAPIDJSON_UNLIKELY(is.Peek() != '"')) - RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); - - ParseString(is, handler, true); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - if (RAPIDJSON_UNLIKELY(!Consume(is, ':'))) - RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - ParseValue(is, handler); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - ++memberCount; - - switch (is.Peek()) { - case ',': - is.Take(); - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - break; - case '}': - is.Take(); - if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - return; - default: - RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy - } - - if (parseFlags & kParseTrailingCommasFlag) { - if (is.Peek() == '}') { - if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - is.Take(); - return; - } - } - } - } - - // Parse array: [ value, ... ] - template - void ParseArray(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == '['); - is.Take(); // Skip '[' - - if (RAPIDJSON_UNLIKELY(!handler.StartArray())) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - if (Consume(is, ']')) { - if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - return; - } - - for (SizeType elementCount = 0;;) { - ParseValue(is, handler); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - ++elementCount; - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - - if (Consume(is, ',')) { - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - } - else if (Consume(is, ']')) { - if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - return; - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); - - if (parseFlags & kParseTrailingCommasFlag) { - if (is.Peek() == ']') { - if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - is.Take(); - return; - } - } - } - } - - template - void ParseNull(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == 'n'); - is.Take(); - - if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) { - if (RAPIDJSON_UNLIKELY(!handler.Null())) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); - } - - template - void ParseTrue(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == 't'); - is.Take(); - - if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) { - if (RAPIDJSON_UNLIKELY(!handler.Bool(true))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); - } - - template - void ParseFalse(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == 'f'); - is.Take(); - - if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) { - if (RAPIDJSON_UNLIKELY(!handler.Bool(false))) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); - } - - template - RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) { - if (RAPIDJSON_LIKELY(is.Peek() == expect)) { - is.Take(); - return true; - } - else - return false; - } - - // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). - template - unsigned ParseHex4(InputStream& is, size_t escapeOffset) { - unsigned codepoint = 0; - for (int i = 0; i < 4; i++) { - Ch c = is.Peek(); - codepoint <<= 4; - codepoint += static_cast(c); - if (c >= '0' && c <= '9') - codepoint -= '0'; - else if (c >= 'A' && c <= 'F') - codepoint -= 'A' - 10; - else if (c >= 'a' && c <= 'f') - codepoint -= 'a' - 10; - else { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); - } - is.Take(); - } - return codepoint; - } - - template - class StackStream { - public: - typedef CharType Ch; - - StackStream(internal::Stack& stack) : stack_(stack), length_(0) {} - RAPIDJSON_FORCEINLINE void Put(Ch c) { - *stack_.template Push() = c; - ++length_; - } - - RAPIDJSON_FORCEINLINE void* Push(SizeType count) { - length_ += count; - return stack_.template Push(count); - } - - size_t Length() const { return length_; } - - Ch* Pop() { - return stack_.template Pop(length_); - } - - private: - StackStream(const StackStream&); - StackStream& operator=(const StackStream&); - - internal::Stack& stack_; - SizeType length_; - }; - - // Parse string and generate String event. Different code paths for kParseInsituFlag. - template - void ParseString(InputStream& is, Handler& handler, bool isKey = false) { - internal::StreamLocalCopy copy(is); - InputStream& s(copy.s); - - RAPIDJSON_ASSERT(s.Peek() == '\"'); - s.Take(); // Skip '\"' - - bool success = false; - if (parseFlags & kParseInsituFlag) { - typename InputStream::Ch *head = s.PutBegin(); - ParseStringToStream(s, s); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - size_t length = s.PutEnd(head) - 1; - RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); - const typename TargetEncoding::Ch* const str = reinterpret_cast(head); - success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); - } - else { - StackStream stackStream(stack_); - ParseStringToStream(s, stackStream); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - SizeType length = static_cast(stackStream.Length()) - 1; - const typename TargetEncoding::Ch* const str = stackStream.Pop(); - success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); - } - if (RAPIDJSON_UNLIKELY(!success)) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); - } - - // Parse string to an output is - // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. - template - RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - static const char escape[256] = { - Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', - Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, - 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, - 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 - }; -#undef Z16 -//!@endcond - - for (;;) { - // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation. - if (!(parseFlags & kParseValidateEncodingFlag)) - ScanCopyUnescapedString(is, os); - - Ch c = is.Peek(); - if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape - size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset - is.Take(); - Ch e = is.Peek(); - if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast(e)])) { - is.Take(); - os.Put(static_cast(escape[static_cast(e)])); - } - else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode - is.Take(); - unsigned codepoint = ParseHex4(is, escapeOffset); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) { - // Handle UTF-16 surrogate pair - if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) - RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); - unsigned codepoint2 = ParseHex4(is, escapeOffset); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) - RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); - codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; - } - TEncoding::Encode(os, codepoint); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset); - } - else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote - is.Take(); - os.Put('\0'); // null-terminate the string - return; - } - else if (RAPIDJSON_UNLIKELY(static_cast(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF - if (c == '\0') - RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); - else - RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell()); - } - else { - size_t offset = is.Tell(); - if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? - !Transcoder::Validate(is, os) : - !Transcoder::Transcode(is, os)))) - RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); - } - } - } - - template - static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) { - // Do nothing for generic version - } - -#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) - // StringStream -> StackStream - static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { - const char* p = is.src_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = p; - return; - } - else - os.Put(*p++); - - // The rest of string using SIMD - static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; - static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; - const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); - const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); - const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); - - for (;; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const __m128i t1 = _mm_cmpeq_epi8(s, dq); - const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 - const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); - unsigned short r = static_cast(_mm_movemask_epi8(x)); - if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped - SizeType length; - #ifdef _MSC_VER // Find the index of first escaped - unsigned long offset; - _BitScanForward(&offset, r); - length = offset; - #else - length = static_cast(__builtin_ffs(r) - 1); - #endif - char* q = reinterpret_cast(os.Push(length)); - for (size_t i = 0; i < length; i++) - q[i] = p[i]; - - p += length; - break; - } - _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); - } - - is.src_ = p; - } - - // InsituStringStream -> InsituStringStream - static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { - RAPIDJSON_ASSERT(&is == &os); - (void)os; - - if (is.src_ == is.dst_) { - SkipUnescapedString(is); - return; - } - - char* p = is.src_; - char *q = is.dst_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - while (p != nextAligned) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = p; - is.dst_ = q; - return; - } - else - *q++ = *p++; - - // The rest of string using SIMD - static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; - static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; - const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); - const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); - const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); - - for (;; p += 16, q += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const __m128i t1 = _mm_cmpeq_epi8(s, dq); - const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 - const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); - unsigned short r = static_cast(_mm_movemask_epi8(x)); - if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped - size_t length; -#ifdef _MSC_VER // Find the index of first escaped - unsigned long offset; - _BitScanForward(&offset, r); - length = offset; -#else - length = static_cast(__builtin_ffs(r) - 1); -#endif - for (const char* pend = p + length; p != pend; ) - *q++ = *p++; - break; - } - _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s); - } - - is.src_ = p; - is.dst_ = q; - } - - // When read/write pointers are the same for insitu stream, just skip unescaped characters - static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { - RAPIDJSON_ASSERT(is.src_ == is.dst_); - char* p = is.src_; - - // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - for (; p != nextAligned; p++) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { - is.src_ = is.dst_ = p; - return; - } - - // The rest of string using SIMD - static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; - static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; - const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); - const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); - const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); - - for (;; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const __m128i t1 = _mm_cmpeq_epi8(s, dq); - const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 - const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); - unsigned short r = static_cast(_mm_movemask_epi8(x)); - if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped - size_t length; -#ifdef _MSC_VER // Find the index of first escaped - unsigned long offset; - _BitScanForward(&offset, r); - length = offset; -#else - length = static_cast(__builtin_ffs(r) - 1); -#endif - p += length; - break; - } - } - - is.src_ = is.dst_ = p; - } -#endif - - template - class NumberStream; - - template - class NumberStream { - public: - typedef typename InputStream::Ch Ch; - - NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } - ~NumberStream() {} - - RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } - RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } - RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } - RAPIDJSON_FORCEINLINE void Push(char) {} - - size_t Tell() { return is.Tell(); } - size_t Length() { return 0; } - const char* Pop() { return 0; } - - protected: - NumberStream& operator=(const NumberStream&); - - InputStream& is; - }; - - template - class NumberStream : public NumberStream { - typedef NumberStream Base; - public: - NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {} - ~NumberStream() {} - - RAPIDJSON_FORCEINLINE Ch TakePush() { - stackStream.Put(static_cast(Base::is.Peek())); - return Base::is.Take(); - } - - RAPIDJSON_FORCEINLINE void Push(char c) { - stackStream.Put(c); - } - - size_t Length() { return stackStream.Length(); } - - const char* Pop() { - stackStream.Put('\0'); - return stackStream.Pop(); - } - - private: - StackStream stackStream; - }; - - template - class NumberStream : public NumberStream { - typedef NumberStream Base; - public: - NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} - ~NumberStream() {} - - RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } - }; - - template - void ParseNumber(InputStream& is, Handler& handler) { - internal::StreamLocalCopy copy(is); - NumberStream s(*this, copy.s); - - size_t startOffset = s.Tell(); - double d = 0.0; - bool useNanOrInf = false; - - // Parse minus - bool minus = Consume(s, '-'); - - // Parse int: zero / ( digit1-9 *DIGIT ) - unsigned i = 0; - uint64_t i64 = 0; - bool use64bit = false; - int significandDigit = 0; - if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) { - i = 0; - s.TakePush(); - } - else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) { - i = static_cast(s.TakePush() - '0'); - - if (minus) - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648 - if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) { - i64 = i; - use64bit = true; - break; - } - } - i = i * 10 + static_cast(s.TakePush() - '0'); - significandDigit++; - } - else - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295 - if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) { - i64 = i; - use64bit = true; - break; - } - } - i = i * 10 + static_cast(s.TakePush() - '0'); - significandDigit++; - } - } - // Parse NaN or Infinity here - else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { - useNanOrInf = true; - if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) { - d = std::numeric_limits::quiet_NaN(); - } - else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) { - d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); - if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') - && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); - - // Parse 64bit int - bool useDouble = false; - if (use64bit) { - if (minus) - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 - if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) { - d = static_cast(i64); - useDouble = true; - break; - } - i64 = i64 * 10 + static_cast(s.TakePush() - '0'); - significandDigit++; - } - else - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615 - if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) { - d = static_cast(i64); - useDouble = true; - break; - } - i64 = i64 * 10 + static_cast(s.TakePush() - '0'); - significandDigit++; - } - } - - // Force double for big integer - if (useDouble) { - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0 - RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); - d = d * 10 + (s.TakePush() - '0'); - } - } - - // Parse frac = decimal-point 1*DIGIT - int expFrac = 0; - size_t decimalPosition; - if (Consume(s, '.')) { - decimalPosition = s.Length(); - - if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) - RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); - - if (!useDouble) { -#if RAPIDJSON_64BIT - // Use i64 to store significand in 64-bit architecture - if (!use64bit) - i64 = i; - - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path - break; - else { - i64 = i64 * 10 + static_cast(s.TakePush() - '0'); - --expFrac; - if (i64 != 0) - significandDigit++; - } - } - - d = static_cast(i64); -#else - // Use double to store significand in 32-bit architecture - d = static_cast(use64bit ? i64 : i); -#endif - useDouble = true; - } - - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (significandDigit < 17) { - d = d * 10.0 + (s.TakePush() - '0'); - --expFrac; - if (RAPIDJSON_LIKELY(d > 0.0)) - significandDigit++; - } - else - s.TakePush(); - } - } - else - decimalPosition = s.Length(); // decimal position at the end of integer. - - // Parse exp = e [ minus / plus ] 1*DIGIT - int exp = 0; - if (Consume(s, 'e') || Consume(s, 'E')) { - if (!useDouble) { - d = static_cast(use64bit ? i64 : i); - useDouble = true; - } - - bool expMinus = false; - if (Consume(s, '+')) - ; - else if (Consume(s, '-')) - expMinus = true; - - if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - exp = static_cast(s.Take() - '0'); - if (expMinus) { - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - exp = exp * 10 + static_cast(s.Take() - '0'); - if (exp >= 214748364) { // Issue #313: prevent overflow exponent - while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent - s.Take(); - } - } - } - else { // positive exp - int maxExp = 308 - expFrac; - while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - exp = exp * 10 + static_cast(s.Take() - '0'); - if (RAPIDJSON_UNLIKELY(exp > maxExp)) - RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); - } - } - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); - - if (expMinus) - exp = -exp; - } - - // Finish parsing, call event according to the type of number. - bool cont = true; - - if (parseFlags & kParseNumbersAsStringsFlag) { - if (parseFlags & kParseInsituFlag) { - s.Pop(); // Pop stack no matter if it will be used or not. - typename InputStream::Ch* head = is.PutBegin(); - const size_t length = s.Tell() - startOffset; - RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); - // unable to insert the \0 character here, it will erase the comma after this number - const typename TargetEncoding::Ch* const str = reinterpret_cast(head); - cont = handler.RawNumber(str, SizeType(length), false); - } - else { - SizeType numCharsToCopy = static_cast(s.Length()); - StringStream srcStream(s.Pop()); - StackStream dstStream(stack_); - while (numCharsToCopy--) { - Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); - } - dstStream.Put('\0'); - const typename TargetEncoding::Ch* str = dstStream.Pop(); - const SizeType length = static_cast(dstStream.Length()) - 1; - cont = handler.RawNumber(str, SizeType(length), true); - } - } - else { - size_t length = s.Length(); - const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. - - if (useDouble) { - int p = exp + expFrac; - if (parseFlags & kParseFullPrecisionFlag) - d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); - else - d = internal::StrtodNormalPrecision(d, p); - - cont = handler.Double(minus ? -d : d); - } - else if (useNanOrInf) { - cont = handler.Double(d); - } - else { - if (use64bit) { - if (minus) - cont = handler.Int64(static_cast(~i64 + 1)); - else - cont = handler.Uint64(i64); - } - else { - if (minus) - cont = handler.Int(static_cast(~i + 1)); - else - cont = handler.Uint(i); - } - } - } - if (RAPIDJSON_UNLIKELY(!cont)) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset); - } - - // Parse any JSON value - template - void ParseValue(InputStream& is, Handler& handler) { - switch (is.Peek()) { - case 'n': ParseNull (is, handler); break; - case 't': ParseTrue (is, handler); break; - case 'f': ParseFalse (is, handler); break; - case '"': ParseString(is, handler); break; - case '{': ParseObject(is, handler); break; - case '[': ParseArray (is, handler); break; - default : - ParseNumber(is, handler); - break; - - } - } - - // Iterative Parsing - - // States - enum IterativeParsingState { - IterativeParsingStartState = 0, - IterativeParsingFinishState, - IterativeParsingErrorState, - - // Object states - IterativeParsingObjectInitialState, - IterativeParsingMemberKeyState, - IterativeParsingKeyValueDelimiterState, - IterativeParsingMemberValueState, - IterativeParsingMemberDelimiterState, - IterativeParsingObjectFinishState, - - // Array states - IterativeParsingArrayInitialState, - IterativeParsingElementState, - IterativeParsingElementDelimiterState, - IterativeParsingArrayFinishState, - - // Single value state - IterativeParsingValueState - }; - - enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 }; - - // Tokens - enum Token { - LeftBracketToken = 0, - RightBracketToken, - - LeftCurlyBracketToken, - RightCurlyBracketToken, - - CommaToken, - ColonToken, - - StringToken, - FalseToken, - TrueToken, - NullToken, - NumberToken, - - kTokenCount - }; - - RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) { - -//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#define N NumberToken -#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N - // Maps from ASCII to Token - static const unsigned char tokenMap[256] = { - N16, // 00~0F - N16, // 10~1F - N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F - N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F - N16, // 40~4F - N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F - N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F - N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F - N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF - }; -#undef N -#undef N16 -//!@endcond - - if (sizeof(Ch) == 1 || static_cast(c) < 256) - return static_cast(tokenMap[static_cast(c)]); - else - return NumberToken; - } - - RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { - // current state x one lookahead token -> new state - static const char G[cIterativeParsingStateCount][kTokenCount] = { - // Start - { - IterativeParsingArrayInitialState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingValueState, // String - IterativeParsingValueState, // False - IterativeParsingValueState, // True - IterativeParsingValueState, // Null - IterativeParsingValueState // Number - }, - // Finish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // Error(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // ObjectInitial - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingObjectFinishState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberKeyState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // MemberKey - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingKeyValueDelimiterState, // Colon - IterativeParsingErrorState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // KeyValueDelimiter - { - IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) - IterativeParsingErrorState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberValueState, // String - IterativeParsingMemberValueState, // False - IterativeParsingMemberValueState, // True - IterativeParsingMemberValueState, // Null - IterativeParsingMemberValueState // Number - }, - // MemberValue - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingObjectFinishState, // Right curly bracket - IterativeParsingMemberDelimiterState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingErrorState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // MemberDelimiter - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingObjectFinishState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberKeyState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // ObjectFinish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // ArrayInitial - { - IterativeParsingArrayInitialState, // Left bracket(push Element state) - IterativeParsingArrayFinishState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push Element state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingElementState, // String - IterativeParsingElementState, // False - IterativeParsingElementState, // True - IterativeParsingElementState, // Null - IterativeParsingElementState // Number - }, - // Element - { - IterativeParsingErrorState, // Left bracket - IterativeParsingArrayFinishState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingErrorState, // Right curly bracket - IterativeParsingElementDelimiterState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingErrorState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // ElementDelimiter - { - IterativeParsingArrayInitialState, // Left bracket(push Element state) - IterativeParsingArrayFinishState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push Element state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingElementState, // String - IterativeParsingElementState, // False - IterativeParsingElementState, // True - IterativeParsingElementState, // Null - IterativeParsingElementState // Number - }, - // ArrayFinish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // Single Value (sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - } - }; // End of G - - return static_cast(G[state][token]); - } - - // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). - // May return a new state on state pop. - template - RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { - (void)token; - - switch (dst) { - case IterativeParsingErrorState: - return dst; - - case IterativeParsingObjectInitialState: - case IterativeParsingArrayInitialState: - { - // Push the state(Element or MemeberValue) if we are nested in another array or value of member. - // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. - IterativeParsingState n = src; - if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) - n = IterativeParsingElementState; - else if (src == IterativeParsingKeyValueDelimiterState) - n = IterativeParsingMemberValueState; - // Push current state. - *stack_.template Push(1) = n; - // Initialize and push the member/element count. - *stack_.template Push(1) = 0; - // Call handler - bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); - // On handler short circuits the parsing. - if (!hr) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); - return IterativeParsingErrorState; - } - else { - is.Take(); - return dst; - } - } - - case IterativeParsingMemberKeyState: - ParseString(is, handler, true); - if (HasParseError()) - return IterativeParsingErrorState; - else - return dst; - - case IterativeParsingKeyValueDelimiterState: - RAPIDJSON_ASSERT(token == ColonToken); - is.Take(); - return dst; - - case IterativeParsingMemberValueState: - // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. - ParseValue(is, handler); - if (HasParseError()) { - return IterativeParsingErrorState; - } - return dst; - - case IterativeParsingElementState: - // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. - ParseValue(is, handler); - if (HasParseError()) { - return IterativeParsingErrorState; - } - return dst; - - case IterativeParsingMemberDelimiterState: - case IterativeParsingElementDelimiterState: - is.Take(); - // Update member/element count. - *stack_.template Top() = *stack_.template Top() + 1; - return dst; - - case IterativeParsingObjectFinishState: - { - // Transit from delimiter is only allowed when trailing commas are enabled - if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell()); - return IterativeParsingErrorState; - } - // Get member count. - SizeType c = *stack_.template Pop(1); - // If the object is not empty, count the last member. - if (src == IterativeParsingMemberValueState) - ++c; - // Restore the state. - IterativeParsingState n = static_cast(*stack_.template Pop(1)); - // Transit to Finish state if this is the topmost scope. - if (n == IterativeParsingStartState) - n = IterativeParsingFinishState; - // Call handler - bool hr = handler.EndObject(c); - // On handler short circuits the parsing. - if (!hr) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); - return IterativeParsingErrorState; - } - else { - is.Take(); - return n; - } - } - - case IterativeParsingArrayFinishState: - { - // Transit from delimiter is only allowed when trailing commas are enabled - if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell()); - return IterativeParsingErrorState; - } - // Get element count. - SizeType c = *stack_.template Pop(1); - // If the array is not empty, count the last element. - if (src == IterativeParsingElementState) - ++c; - // Restore the state. - IterativeParsingState n = static_cast(*stack_.template Pop(1)); - // Transit to Finish state if this is the topmost scope. - if (n == IterativeParsingStartState) - n = IterativeParsingFinishState; - // Call handler - bool hr = handler.EndArray(c); - // On handler short circuits the parsing. - if (!hr) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); - return IterativeParsingErrorState; - } - else { - is.Take(); - return n; - } - } - - default: - // This branch is for IterativeParsingValueState actually. - // Use `default:` rather than - // `case IterativeParsingValueState:` is for code coverage. - - // The IterativeParsingStartState is not enumerated in this switch-case. - // It is impossible for that case. And it can be caught by following assertion. - - // The IterativeParsingFinishState is not enumerated in this switch-case either. - // It is a "derivative" state which cannot triggered from Predict() directly. - // Therefore it cannot happen here. And it can be caught by following assertion. - RAPIDJSON_ASSERT(dst == IterativeParsingValueState); - - // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. - ParseValue(is, handler); - if (HasParseError()) { - return IterativeParsingErrorState; - } - return IterativeParsingFinishState; - } - } - - template - void HandleError(IterativeParsingState src, InputStream& is) { - if (HasParseError()) { - // Error flag has been set. - return; - } - - switch (src) { - case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; - case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; - case IterativeParsingObjectInitialState: - case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; - case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; - case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; - case IterativeParsingKeyValueDelimiterState: - case IterativeParsingArrayInitialState: - case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return; - default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; - } - } - - template - ParseResult IterativeParse(InputStream& is, Handler& handler) { - parseResult_.Clear(); - ClearStackOnExit scope(*this); - IterativeParsingState state = IterativeParsingStartState; - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - while (is.Peek() != '\0') { - Token t = Tokenize(is.Peek()); - IterativeParsingState n = Predict(state, t); - IterativeParsingState d = Transit(state, t, n, is, handler); - - if (d == IterativeParsingErrorState) { - HandleError(state, is); - break; - } - - state = d; - - // Do not further consume streams if a root JSON has been parsed. - if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) - break; - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - } - - // Handle the end of file. - if (state != IterativeParsingFinishState) - HandleError(state, is); - - return parseResult_; - } - - static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. - internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. - ParseResult parseResult_; -}; // class GenericReader - -//! Reader with UTF8 encoding and default allocator. -typedef GenericReader, UTF8<> > Reader; - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - - -#ifdef __GNUC__ -RAPIDJSON_DIAG_POP -#endif - -#ifdef _MSC_VER -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_READER_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/schema.h b/src/Native/libcryptonight/3rdparty/rapidjson/schema.h deleted file mode 100644 index b182aa27f..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/schema.h +++ /dev/null @@ -1,2006 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available-> -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License-> You may obtain a copy of the License at -// -// http://opensource->org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied-> See the License for the -// specific language governing permissions and limitations under the License-> - -#ifndef RAPIDJSON_SCHEMA_H_ -#define RAPIDJSON_SCHEMA_H_ - -#include "document.h" -#include "pointer.h" -#include // abs, floor - -#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) -#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 -#else -#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 -#endif - -#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) -#define RAPIDJSON_SCHEMA_USE_STDREGEX 1 -#else -#define RAPIDJSON_SCHEMA_USE_STDREGEX 0 -#endif - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX -#include "internal/regex.h" -#elif RAPIDJSON_SCHEMA_USE_STDREGEX -#include -#endif - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX -#define RAPIDJSON_SCHEMA_HAS_REGEX 1 -#else -#define RAPIDJSON_SCHEMA_HAS_REGEX 0 -#endif - -#ifndef RAPIDJSON_SCHEMA_VERBOSE -#define RAPIDJSON_SCHEMA_VERBOSE 0 -#endif - -#if RAPIDJSON_SCHEMA_VERBOSE -#include "stringbuffer.h" -#endif - -RAPIDJSON_DIAG_PUSH - -#if defined(__GNUC__) -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_OFF(weak-vtables) -RAPIDJSON_DIAG_OFF(exit-time-destructors) -RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) -RAPIDJSON_DIAG_OFF(variadic-macros) -#endif - -#ifdef _MSC_VER -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// Verbose Utilities - -#if RAPIDJSON_SCHEMA_VERBOSE - -namespace internal { - -inline void PrintInvalidKeyword(const char* keyword) { - printf("Fail keyword: %s\n", keyword); -} - -inline void PrintInvalidKeyword(const wchar_t* keyword) { - wprintf(L"Fail keyword: %ls\n", keyword); -} - -inline void PrintInvalidDocument(const char* document) { - printf("Fail document: %s\n\n", document); -} - -inline void PrintInvalidDocument(const wchar_t* document) { - wprintf(L"Fail document: %ls\n\n", document); -} - -inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) { - printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d); -} - -inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) { - wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d); -} - -} // namespace internal - -#endif // RAPIDJSON_SCHEMA_VERBOSE - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_INVALID_KEYWORD_RETURN - -#if RAPIDJSON_SCHEMA_VERBOSE -#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) -#else -#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) -#endif - -#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\ -RAPIDJSON_MULTILINEMACRO_BEGIN\ - context.invalidKeyword = keyword.GetString();\ - RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\ - return false;\ -RAPIDJSON_MULTILINEMACRO_END - -/////////////////////////////////////////////////////////////////////////////// -// Forward declarations - -template -class GenericSchemaDocument; - -namespace internal { - -template -class Schema; - -/////////////////////////////////////////////////////////////////////////////// -// ISchemaValidator - -class ISchemaValidator { -public: - virtual ~ISchemaValidator() {} - virtual bool IsValid() const = 0; -}; - -/////////////////////////////////////////////////////////////////////////////// -// ISchemaStateFactory - -template -class ISchemaStateFactory { -public: - virtual ~ISchemaStateFactory() {} - virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0; - virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; - virtual void* CreateHasher() = 0; - virtual uint64_t GetHashCode(void* hasher) = 0; - virtual void DestroryHasher(void* hasher) = 0; - virtual void* MallocState(size_t size) = 0; - virtual void FreeState(void* p) = 0; -}; - -/////////////////////////////////////////////////////////////////////////////// -// Hasher - -// For comparison of compound value -template -class Hasher { -public: - typedef typename Encoding::Ch Ch; - - Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} - - bool Null() { return WriteType(kNullType); } - bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); } - bool Int(int i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } - bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } - bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } - bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } - bool Double(double d) { - Number n; - if (d < 0) n.u.i = static_cast(d); - else n.u.u = static_cast(d); - n.d = d; - return WriteNumber(n); - } - - bool RawNumber(const Ch* str, SizeType len, bool) { - WriteBuffer(kNumberType, str, len * sizeof(Ch)); - return true; - } - - bool String(const Ch* str, SizeType len, bool) { - WriteBuffer(kStringType, str, len * sizeof(Ch)); - return true; - } - - bool StartObject() { return true; } - bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); } - bool EndObject(SizeType memberCount) { - uint64_t h = Hash(0, kObjectType); - uint64_t* kv = stack_.template Pop(memberCount * 2); - for (SizeType i = 0; i < memberCount; i++) - h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive - *stack_.template Push() = h; - return true; - } - - bool StartArray() { return true; } - bool EndArray(SizeType elementCount) { - uint64_t h = Hash(0, kArrayType); - uint64_t* e = stack_.template Pop(elementCount); - for (SizeType i = 0; i < elementCount; i++) - h = Hash(h, e[i]); // Use hash to achieve element order sensitive - *stack_.template Push() = h; - return true; - } - - bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); } - - uint64_t GetHashCode() const { - RAPIDJSON_ASSERT(IsValid()); - return *stack_.template Top(); - } - -private: - static const size_t kDefaultSize = 256; - struct Number { - union U { - uint64_t u; - int64_t i; - }u; - double d; - }; - - bool WriteType(Type type) { return WriteBuffer(type, 0, 0); } - - bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); } - - bool WriteBuffer(Type type, const void* data, size_t len) { - // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ - uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); - const unsigned char* d = static_cast(data); - for (size_t i = 0; i < len; i++) - h = Hash(h, d[i]); - *stack_.template Push() = h; - return true; - } - - static uint64_t Hash(uint64_t h, uint64_t d) { - static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); - h ^= d; - h *= kPrime; - return h; - } - - Stack stack_; -}; - -/////////////////////////////////////////////////////////////////////////////// -// SchemaValidationContext - -template -struct SchemaValidationContext { - typedef Schema SchemaType; - typedef ISchemaStateFactory SchemaValidatorFactoryType; - typedef typename SchemaType::ValueType ValueType; - typedef typename ValueType::Ch Ch; - - enum PatternValidatorType { - kPatternValidatorOnly, - kPatternValidatorWithProperty, - kPatternValidatorWithAdditionalProperty - }; - - SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) : - factory(f), - schema(s), - valueSchema(), - invalidKeyword(), - hasher(), - arrayElementHashCodes(), - validators(), - validatorCount(), - patternPropertiesValidators(), - patternPropertiesValidatorCount(), - patternPropertiesSchemas(), - patternPropertiesSchemaCount(), - valuePatternValidatorType(kPatternValidatorOnly), - propertyExist(), - inArray(false), - valueUniqueness(false), - arrayUniqueness(false) - { - } - - ~SchemaValidationContext() { - if (hasher) - factory.DestroryHasher(hasher); - if (validators) { - for (SizeType i = 0; i < validatorCount; i++) - factory.DestroySchemaValidator(validators[i]); - factory.FreeState(validators); - } - if (patternPropertiesValidators) { - for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) - factory.DestroySchemaValidator(patternPropertiesValidators[i]); - factory.FreeState(patternPropertiesValidators); - } - if (patternPropertiesSchemas) - factory.FreeState(patternPropertiesSchemas); - if (propertyExist) - factory.FreeState(propertyExist); - } - - SchemaValidatorFactoryType& factory; - const SchemaType* schema; - const SchemaType* valueSchema; - const Ch* invalidKeyword; - void* hasher; // Only validator access - void* arrayElementHashCodes; // Only validator access this - ISchemaValidator** validators; - SizeType validatorCount; - ISchemaValidator** patternPropertiesValidators; - SizeType patternPropertiesValidatorCount; - const SchemaType** patternPropertiesSchemas; - SizeType patternPropertiesSchemaCount; - PatternValidatorType valuePatternValidatorType; - PatternValidatorType objectPatternValidatorType; - SizeType arrayElementIndex; - bool* propertyExist; - bool inArray; - bool valueUniqueness; - bool arrayUniqueness; -}; - -/////////////////////////////////////////////////////////////////////////////// -// Schema - -template -class Schema { -public: - typedef typename SchemaDocumentType::ValueType ValueType; - typedef typename SchemaDocumentType::AllocatorType AllocatorType; - typedef typename SchemaDocumentType::PointerType PointerType; - typedef typename ValueType::EncodingType EncodingType; - typedef typename EncodingType::Ch Ch; - typedef SchemaValidationContext Context; - typedef Schema SchemaType; - typedef GenericValue SValue; - friend class GenericSchemaDocument; - - Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : - allocator_(allocator), - enum_(), - enumCount_(), - not_(), - type_((1 << kTotalSchemaType) - 1), // typeless - validatorCount_(), - properties_(), - additionalPropertiesSchema_(), - patternProperties_(), - patternPropertyCount_(), - propertyCount_(), - minProperties_(), - maxProperties_(SizeType(~0)), - additionalProperties_(true), - hasDependencies_(), - hasRequired_(), - hasSchemaDependencies_(), - additionalItemsSchema_(), - itemsList_(), - itemsTuple_(), - itemsTupleCount_(), - minItems_(), - maxItems_(SizeType(~0)), - additionalItems_(true), - uniqueItems_(false), - pattern_(), - minLength_(0), - maxLength_(~SizeType(0)), - exclusiveMinimum_(false), - exclusiveMaximum_(false) - { - typedef typename SchemaDocumentType::ValueType ValueType; - typedef typename ValueType::ConstValueIterator ConstValueIterator; - typedef typename ValueType::ConstMemberIterator ConstMemberIterator; - - if (!value.IsObject()) - return; - - if (const ValueType* v = GetMember(value, GetTypeString())) { - type_ = 0; - if (v->IsString()) - AddType(*v); - else if (v->IsArray()) - for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) - AddType(*itr); - } - - if (const ValueType* v = GetMember(value, GetEnumString())) - if (v->IsArray() && v->Size() > 0) { - enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); - for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { - typedef Hasher > EnumHasherType; - char buffer[256 + 24]; - MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); - EnumHasherType h(&hasherAllocator, 256); - itr->Accept(h); - enum_[enumCount_++] = h.GetHashCode(); - } - } - - if (schemaDocument) { - AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); - AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); - AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); - } - - if (const ValueType* v = GetMember(value, GetNotString())) { - schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); - notValidatorIndex_ = validatorCount_; - validatorCount_++; - } - - // Object - - const ValueType* properties = GetMember(value, GetPropertiesString()); - const ValueType* required = GetMember(value, GetRequiredString()); - const ValueType* dependencies = GetMember(value, GetDependenciesString()); - { - // Gather properties from properties/required/dependencies - SValue allProperties(kArrayType); - - if (properties && properties->IsObject()) - for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) - AddUniqueElement(allProperties, itr->name); - - if (required && required->IsArray()) - for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) - if (itr->IsString()) - AddUniqueElement(allProperties, *itr); - - if (dependencies && dependencies->IsObject()) - for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { - AddUniqueElement(allProperties, itr->name); - if (itr->value.IsArray()) - for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i) - if (i->IsString()) - AddUniqueElement(allProperties, *i); - } - - if (allProperties.Size() > 0) { - propertyCount_ = allProperties.Size(); - properties_ = static_cast(allocator_->Malloc(sizeof(Property) * propertyCount_)); - for (SizeType i = 0; i < propertyCount_; i++) { - new (&properties_[i]) Property(); - properties_[i].name = allProperties[i]; - properties_[i].schema = GetTypeless(); - } - } - } - - if (properties && properties->IsObject()) { - PointerType q = p.Append(GetPropertiesString(), allocator_); - for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { - SizeType index; - if (FindPropertyIndex(itr->name, &index)) - schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document); - } - } - - if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { - PointerType q = p.Append(GetPatternPropertiesString(), allocator_); - patternProperties_ = static_cast(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); - patternPropertyCount_ = 0; - - for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { - new (&patternProperties_[patternPropertyCount_]) PatternProperty(); - patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); - schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document); - patternPropertyCount_++; - } - } - - if (required && required->IsArray()) - for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) - if (itr->IsString()) { - SizeType index; - if (FindPropertyIndex(*itr, &index)) { - properties_[index].required = true; - hasRequired_ = true; - } - } - - if (dependencies && dependencies->IsObject()) { - PointerType q = p.Append(GetDependenciesString(), allocator_); - hasDependencies_ = true; - for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { - SizeType sourceIndex; - if (FindPropertyIndex(itr->name, &sourceIndex)) { - if (itr->value.IsArray()) { - properties_[sourceIndex].dependencies = static_cast(allocator_->Malloc(sizeof(bool) * propertyCount_)); - std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_); - for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) { - SizeType targetIndex; - if (FindPropertyIndex(*targetItr, &targetIndex)) - properties_[sourceIndex].dependencies[targetIndex] = true; - } - } - else if (itr->value.IsObject()) { - hasSchemaDependencies_ = true; - schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document); - properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; - validatorCount_++; - } - } - } - } - - if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) { - if (v->IsBool()) - additionalProperties_ = v->GetBool(); - else if (v->IsObject()) - schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document); - } - - AssignIfExist(minProperties_, value, GetMinPropertiesString()); - AssignIfExist(maxProperties_, value, GetMaxPropertiesString()); - - // Array - if (const ValueType* v = GetMember(value, GetItemsString())) { - PointerType q = p.Append(GetItemsString(), allocator_); - if (v->IsObject()) // List validation - schemaDocument->CreateSchema(&itemsList_, q, *v, document); - else if (v->IsArray()) { // Tuple validation - itemsTuple_ = static_cast(allocator_->Malloc(sizeof(const Schema*) * v->Size())); - SizeType index = 0; - for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) - schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document); - } - } - - AssignIfExist(minItems_, value, GetMinItemsString()); - AssignIfExist(maxItems_, value, GetMaxItemsString()); - - if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) { - if (v->IsBool()) - additionalItems_ = v->GetBool(); - else if (v->IsObject()) - schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document); - } - - AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); - - // String - AssignIfExist(minLength_, value, GetMinLengthString()); - AssignIfExist(maxLength_, value, GetMaxLengthString()); - - if (const ValueType* v = GetMember(value, GetPatternString())) - pattern_ = CreatePattern(*v); - - // Number - if (const ValueType* v = GetMember(value, GetMinimumString())) - if (v->IsNumber()) - minimum_.CopyFrom(*v, *allocator_); - - if (const ValueType* v = GetMember(value, GetMaximumString())) - if (v->IsNumber()) - maximum_.CopyFrom(*v, *allocator_); - - AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString()); - AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString()); - - if (const ValueType* v = GetMember(value, GetMultipleOfString())) - if (v->IsNumber() && v->GetDouble() > 0.0) - multipleOf_.CopyFrom(*v, *allocator_); - } - - ~Schema() { - if (allocator_) { - allocator_->Free(enum_); - } - if (properties_) { - for (SizeType i = 0; i < propertyCount_; i++) - properties_[i].~Property(); - AllocatorType::Free(properties_); - } - if (patternProperties_) { - for (SizeType i = 0; i < patternPropertyCount_; i++) - patternProperties_[i].~PatternProperty(); - AllocatorType::Free(patternProperties_); - } - AllocatorType::Free(itemsTuple_); -#if RAPIDJSON_SCHEMA_HAS_REGEX - if (pattern_) { - pattern_->~RegexType(); - allocator_->Free(pattern_); - } -#endif - } - - bool BeginValue(Context& context) const { - if (context.inArray) { - if (uniqueItems_) - context.valueUniqueness = true; - - if (itemsList_) - context.valueSchema = itemsList_; - else if (itemsTuple_) { - if (context.arrayElementIndex < itemsTupleCount_) - context.valueSchema = itemsTuple_[context.arrayElementIndex]; - else if (additionalItemsSchema_) - context.valueSchema = additionalItemsSchema_; - else if (additionalItems_) - context.valueSchema = GetTypeless(); - else - RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); - } - else - context.valueSchema = GetTypeless(); - - context.arrayElementIndex++; - } - return true; - } - - RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { - if (context.patternPropertiesValidatorCount > 0) { - bool otherValid = false; - SizeType count = context.patternPropertiesValidatorCount; - if (context.objectPatternValidatorType != Context::kPatternValidatorOnly) - otherValid = context.patternPropertiesValidators[--count]->IsValid(); - - bool patternValid = true; - for (SizeType i = 0; i < count; i++) - if (!context.patternPropertiesValidators[i]->IsValid()) { - patternValid = false; - break; - } - - if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { - if (!patternValid) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); - } - else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { - if (!patternValid || !otherValid) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); - } - else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); - } - - if (enum_) { - const uint64_t h = context.factory.GetHashCode(context.hasher); - for (SizeType i = 0; i < enumCount_; i++) - if (enum_[i] == h) - goto foundEnum; - RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString()); - foundEnum:; - } - - if (allOf_.schemas) - for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) - if (!context.validators[i]->IsValid()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString()); - - if (anyOf_.schemas) { - for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) - if (context.validators[i]->IsValid()) - goto foundAny; - RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString()); - foundAny:; - } - - if (oneOf_.schemas) { - bool oneValid = false; - for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) - if (context.validators[i]->IsValid()) { - if (oneValid) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); - else - oneValid = true; - } - if (!oneValid) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); - } - - if (not_ && context.validators[notValidatorIndex_]->IsValid()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString()); - - return true; - } - - bool Null(Context& context) const { - if (!(type_ & (1 << kNullSchemaType))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - return CreateParallelValidator(context); - } - - bool Bool(Context& context, bool) const { - if (!(type_ & (1 << kBooleanSchemaType))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - return CreateParallelValidator(context); - } - - bool Int(Context& context, int i) const { - if (!CheckInt(context, i)) - return false; - return CreateParallelValidator(context); - } - - bool Uint(Context& context, unsigned u) const { - if (!CheckUint(context, u)) - return false; - return CreateParallelValidator(context); - } - - bool Int64(Context& context, int64_t i) const { - if (!CheckInt(context, i)) - return false; - return CreateParallelValidator(context); - } - - bool Uint64(Context& context, uint64_t u) const { - if (!CheckUint(context, u)) - return false; - return CreateParallelValidator(context); - } - - bool Double(Context& context, double d) const { - if (!(type_ & (1 << kNumberSchemaType))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - - if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) - return false; - - if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) - return false; - - if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) - return false; - - return CreateParallelValidator(context); - } - - bool String(Context& context, const Ch* str, SizeType length, bool) const { - if (!(type_ & (1 << kStringSchemaType))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - - if (minLength_ != 0 || maxLength_ != SizeType(~0)) { - SizeType count; - if (internal::CountStringCodePoint(str, length, &count)) { - if (count < minLength_) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString()); - if (count > maxLength_) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString()); - } - } - - if (pattern_ && !IsPatternMatch(pattern_, str, length)) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString()); - - return CreateParallelValidator(context); - } - - bool StartObject(Context& context) const { - if (!(type_ & (1 << kObjectSchemaType))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - - if (hasDependencies_ || hasRequired_) { - context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); - std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); - } - - if (patternProperties_) { // pre-allocate schema array - SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType - context.patternPropertiesSchemas = static_cast(context.factory.MallocState(sizeof(const SchemaType*) * count)); - context.patternPropertiesSchemaCount = 0; - std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count); - } - - return CreateParallelValidator(context); - } - - bool Key(Context& context, const Ch* str, SizeType len, bool) const { - if (patternProperties_) { - context.patternPropertiesSchemaCount = 0; - for (SizeType i = 0; i < patternPropertyCount_; i++) - if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) - context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; - } - - SizeType index; - if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { - if (context.patternPropertiesSchemaCount > 0) { - context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; - context.valueSchema = GetTypeless(); - context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; - } - else - context.valueSchema = properties_[index].schema; - - if (context.propertyExist) - context.propertyExist[index] = true; - - return true; - } - - if (additionalPropertiesSchema_) { - if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) { - context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; - context.valueSchema = GetTypeless(); - context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; - } - else - context.valueSchema = additionalPropertiesSchema_; - return true; - } - else if (additionalProperties_) { - context.valueSchema = GetTypeless(); - return true; - } - - if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties - RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString()); - - return true; - } - - bool EndObject(Context& context, SizeType memberCount) const { - if (hasRequired_) - for (SizeType index = 0; index < propertyCount_; index++) - if (properties_[index].required) - if (!context.propertyExist[index]) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); - - if (memberCount < minProperties_) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); - - if (memberCount > maxProperties_) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); - - if (hasDependencies_) { - for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) - if (context.propertyExist[sourceIndex]) { - if (properties_[sourceIndex].dependencies) { - for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) - if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex]) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); - } - else if (properties_[sourceIndex].dependenciesSchema) - if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); - } - } - - return true; - } - - bool StartArray(Context& context) const { - if (!(type_ & (1 << kArraySchemaType))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - - context.arrayElementIndex = 0; - context.inArray = true; - - return CreateParallelValidator(context); - } - - bool EndArray(Context& context, SizeType elementCount) const { - context.inArray = false; - - if (elementCount < minItems_) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString()); - - if (elementCount > maxItems_) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString()); - - return true; - } - - // Generate functions for string literal according to Ch -#define RAPIDJSON_STRING_(name, ...) \ - static const ValueType& Get##name##String() {\ - static const Ch s[] = { __VA_ARGS__, '\0' };\ - static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\ - return v;\ - } - - RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') - RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') - RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') - RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') - RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') - RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') - RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') - RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') - RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') - RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') - RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') - RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') - RAPIDJSON_STRING_(Not, 'n', 'o', 't') - RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') - RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') - RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') - RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') - RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') - RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') - -#undef RAPIDJSON_STRING_ - -private: - enum SchemaValueType { - kNullSchemaType, - kBooleanSchemaType, - kObjectSchemaType, - kArraySchemaType, - kStringSchemaType, - kNumberSchemaType, - kIntegerSchemaType, - kTotalSchemaType - }; - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX - typedef internal::GenericRegex RegexType; -#elif RAPIDJSON_SCHEMA_USE_STDREGEX - typedef std::basic_regex RegexType; -#else - typedef char RegexType; -#endif - - struct SchemaArray { - SchemaArray() : schemas(), count() {} - ~SchemaArray() { AllocatorType::Free(schemas); } - const SchemaType** schemas; - SizeType begin; // begin index of context.validators - SizeType count; - }; - - static const SchemaType* GetTypeless() { - static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0); - return &typeless; - } - - template - void AddUniqueElement(V1& a, const V2& v) { - for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) - if (*itr == v) - return; - V1 c(v, *allocator_); - a.PushBack(c, *allocator_); - } - - static const ValueType* GetMember(const ValueType& value, const ValueType& name) { - typename ValueType::ConstMemberIterator itr = value.FindMember(name); - return itr != value.MemberEnd() ? &(itr->value) : 0; - } - - static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) { - if (const ValueType* v = GetMember(value, name)) - if (v->IsBool()) - out = v->GetBool(); - } - - static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) { - if (const ValueType* v = GetMember(value, name)) - if (v->IsUint64() && v->GetUint64() <= SizeType(~0)) - out = static_cast(v->GetUint64()); - } - - void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) { - if (const ValueType* v = GetMember(value, name)) { - if (v->IsArray() && v->Size() > 0) { - PointerType q = p.Append(name, allocator_); - out.count = v->Size(); - out.schemas = static_cast(allocator_->Malloc(out.count * sizeof(const Schema*))); - memset(out.schemas, 0, sizeof(Schema*)* out.count); - for (SizeType i = 0; i < out.count; i++) - schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document); - out.begin = validatorCount_; - validatorCount_ += out.count; - } - } - } - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX - template - RegexType* CreatePattern(const ValueType& value) { - if (value.IsString()) { - RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString()); - if (!r->IsValid()) { - r->~RegexType(); - AllocatorType::Free(r); - r = 0; - } - return r; - } - return 0; - } - - static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { - return pattern->Search(str); - } -#elif RAPIDJSON_SCHEMA_USE_STDREGEX - template - RegexType* CreatePattern(const ValueType& value) { - if (value.IsString()) - try { - return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); - } - catch (const std::regex_error&) { - } - return 0; - } - - static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) { - std::match_results r; - return std::regex_search(str, str + length, r, *pattern); - } -#else - template - RegexType* CreatePattern(const ValueType&) { return 0; } - - static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } -#endif // RAPIDJSON_SCHEMA_USE_STDREGEX - - void AddType(const ValueType& type) { - if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; - else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType; - else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType; - else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType; - else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType; - else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType; - else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); - } - - bool CreateParallelValidator(Context& context) const { - if (enum_ || context.arrayUniqueness) - context.hasher = context.factory.CreateHasher(); - - if (validatorCount_) { - RAPIDJSON_ASSERT(context.validators == 0); - context.validators = static_cast(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); - context.validatorCount = validatorCount_; - - if (allOf_.schemas) - CreateSchemaValidators(context, allOf_); - - if (anyOf_.schemas) - CreateSchemaValidators(context, anyOf_); - - if (oneOf_.schemas) - CreateSchemaValidators(context, oneOf_); - - if (not_) - context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_); - - if (hasSchemaDependencies_) { - for (SizeType i = 0; i < propertyCount_; i++) - if (properties_[i].dependenciesSchema) - context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema); - } - } - - return true; - } - - void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const { - for (SizeType i = 0; i < schemas.count; i++) - context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]); - } - - // O(n) - bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const { - SizeType len = name.GetStringLength(); - const Ch* str = name.GetString(); - for (SizeType index = 0; index < propertyCount_; index++) - if (properties_[index].name.GetStringLength() == len && - (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) - { - *outIndex = index; - return true; - } - return false; - } - - bool CheckInt(Context& context, int64_t i) const { - if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - - if (!minimum_.IsNull()) { - if (minimum_.IsInt64()) { - if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); - } - else if (minimum_.IsUint64()) { - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64() - } - else if (!CheckDoubleMinimum(context, static_cast(i))) - return false; - } - - if (!maximum_.IsNull()) { - if (maximum_.IsInt64()) { - if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); - } - else if (maximum_.IsUint64()) - /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64() - else if (!CheckDoubleMaximum(context, static_cast(i))) - return false; - } - - if (!multipleOf_.IsNull()) { - if (multipleOf_.IsUint64()) { - if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); - } - else if (!CheckDoubleMultipleOf(context, static_cast(i))) - return false; - } - - return true; - } - - bool CheckUint(Context& context, uint64_t i) const { - if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - - if (!minimum_.IsNull()) { - if (minimum_.IsUint64()) { - if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); - } - else if (minimum_.IsInt64()) - /* do nothing */; // i >= 0 > minimum.Getint64() - else if (!CheckDoubleMinimum(context, static_cast(i))) - return false; - } - - if (!maximum_.IsNull()) { - if (maximum_.IsUint64()) { - if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); - } - else if (maximum_.IsInt64()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_ - else if (!CheckDoubleMaximum(context, static_cast(i))) - return false; - } - - if (!multipleOf_.IsNull()) { - if (multipleOf_.IsUint64()) { - if (i % multipleOf_.GetUint64() != 0) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); - } - else if (!CheckDoubleMultipleOf(context, static_cast(i))) - return false; - } - - return true; - } - - bool CheckDoubleMinimum(Context& context, double d) const { - if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); - return true; - } - - bool CheckDoubleMaximum(Context& context, double d) const { - if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); - return true; - } - - bool CheckDoubleMultipleOf(Context& context, double d) const { - double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); - double q = std::floor(a / b); - double r = a - q * b; - if (r > 0.0) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); - return true; - } - - struct Property { - Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} - ~Property() { AllocatorType::Free(dependencies); } - SValue name; - const SchemaType* schema; - const SchemaType* dependenciesSchema; - SizeType dependenciesValidatorIndex; - bool* dependencies; - bool required; - }; - - struct PatternProperty { - PatternProperty() : schema(), pattern() {} - ~PatternProperty() { - if (pattern) { - pattern->~RegexType(); - AllocatorType::Free(pattern); - } - } - const SchemaType* schema; - RegexType* pattern; - }; - - AllocatorType* allocator_; - uint64_t* enum_; - SizeType enumCount_; - SchemaArray allOf_; - SchemaArray anyOf_; - SchemaArray oneOf_; - const SchemaType* not_; - unsigned type_; // bitmask of kSchemaType - SizeType validatorCount_; - SizeType notValidatorIndex_; - - Property* properties_; - const SchemaType* additionalPropertiesSchema_; - PatternProperty* patternProperties_; - SizeType patternPropertyCount_; - SizeType propertyCount_; - SizeType minProperties_; - SizeType maxProperties_; - bool additionalProperties_; - bool hasDependencies_; - bool hasRequired_; - bool hasSchemaDependencies_; - - const SchemaType* additionalItemsSchema_; - const SchemaType* itemsList_; - const SchemaType** itemsTuple_; - SizeType itemsTupleCount_; - SizeType minItems_; - SizeType maxItems_; - bool additionalItems_; - bool uniqueItems_; - - RegexType* pattern_; - SizeType minLength_; - SizeType maxLength_; - - SValue minimum_; - SValue maximum_; - SValue multipleOf_; - bool exclusiveMinimum_; - bool exclusiveMaximum_; -}; - -template -struct TokenHelper { - RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { - *documentStack.template Push() = '/'; - char buffer[21]; - size_t length = static_cast((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); - for (size_t i = 0; i < length; i++) - *documentStack.template Push() = buffer[i]; - } -}; - -// Partial specialized version for char to prevent buffer copying. -template -struct TokenHelper { - RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { - if (sizeof(SizeType) == 4) { - char *buffer = documentStack.template Push(1 + 10); // '/' + uint - *buffer++ = '/'; - const char* end = internal::u32toa(index, buffer); - documentStack.template Pop(static_cast(10 - (end - buffer))); - } - else { - char *buffer = documentStack.template Push(1 + 20); // '/' + uint64 - *buffer++ = '/'; - const char* end = internal::u64toa(index, buffer); - documentStack.template Pop(static_cast(20 - (end - buffer))); - } - } -}; - -} // namespace internal - -/////////////////////////////////////////////////////////////////////////////// -// IGenericRemoteSchemaDocumentProvider - -template -class IGenericRemoteSchemaDocumentProvider { -public: - typedef typename SchemaDocumentType::Ch Ch; - - virtual ~IGenericRemoteSchemaDocumentProvider() {} - virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; -}; - -/////////////////////////////////////////////////////////////////////////////// -// GenericSchemaDocument - -//! JSON schema document. -/*! - A JSON schema document is a compiled version of a JSON schema. - It is basically a tree of internal::Schema. - - \note This is an immutable class (i.e. its instance cannot be modified after construction). - \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding. - \tparam Allocator Allocator type for allocating memory of this document. -*/ -template -class GenericSchemaDocument { -public: - typedef ValueT ValueType; - typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProviderType; - typedef Allocator AllocatorType; - typedef typename ValueType::EncodingType EncodingType; - typedef typename EncodingType::Ch Ch; - typedef internal::Schema SchemaType; - typedef GenericPointer PointerType; - friend class internal::Schema; - template - friend class GenericSchemaValidator; - - //! Constructor. - /*! - Compile a JSON document into schema document. - - \param document A JSON document as source. - \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. - \param allocator An optional allocator instance for allocating memory. Can be null. - */ - explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : - remoteProvider_(remoteProvider), - allocator_(allocator), - ownAllocator_(), - root_(), - schemaMap_(allocator, kInitialSchemaMapSize), - schemaRef_(allocator, kInitialSchemaRefSize) - { - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); - - // Generate root schema, it will call CreateSchema() to create sub-schemas, - // And call AddRefSchema() if there are $ref. - CreateSchemaRecursive(&root_, PointerType(), document, document); - - // Resolve $ref - while (!schemaRef_.Empty()) { - SchemaRefEntry* refEntry = schemaRef_.template Pop(1); - if (const SchemaType* s = GetSchema(refEntry->target)) { - if (refEntry->schema) - *refEntry->schema = s; - - // Create entry in map if not exist - if (!GetSchema(refEntry->source)) { - new (schemaMap_.template Push()) SchemaEntry(refEntry->source, const_cast(s), false, allocator_); - } - } - refEntry->~SchemaRefEntry(); - } - - RAPIDJSON_ASSERT(root_ != 0); - - schemaRef_.ShrinkToFit(); // Deallocate all memory for ref - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move constructor in C++11 - GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT : - remoteProvider_(rhs.remoteProvider_), - allocator_(rhs.allocator_), - ownAllocator_(rhs.ownAllocator_), - root_(rhs.root_), - schemaMap_(std::move(rhs.schemaMap_)), - schemaRef_(std::move(rhs.schemaRef_)) - { - rhs.remoteProvider_ = 0; - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - } -#endif - - //! Destructor - ~GenericSchemaDocument() { - while (!schemaMap_.Empty()) - schemaMap_.template Pop(1)->~SchemaEntry(); - - RAPIDJSON_DELETE(ownAllocator_); - } - - //! Get the root schema. - const SchemaType& GetRoot() const { return *root_; } - -private: - //! Prohibit copying - GenericSchemaDocument(const GenericSchemaDocument&); - //! Prohibit assignment - GenericSchemaDocument& operator=(const GenericSchemaDocument&); - - struct SchemaRefEntry { - SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {} - PointerType source; - PointerType target; - const SchemaType** schema; - }; - - struct SchemaEntry { - SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} - ~SchemaEntry() { - if (owned) { - schema->~SchemaType(); - Allocator::Free(schema); - } - } - PointerType pointer; - SchemaType* schema; - bool owned; - }; - - void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { - if (schema) - *schema = SchemaType::GetTypeless(); - - if (v.GetType() == kObjectType) { - const SchemaType* s = GetSchema(pointer); - if (!s) - CreateSchema(schema, pointer, v, document); - - for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) - CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); - } - else if (v.GetType() == kArrayType) - for (SizeType i = 0; i < v.Size(); i++) - CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document); - } - - void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { - RAPIDJSON_ASSERT(pointer.IsValid()); - if (v.IsObject()) { - if (!HandleRefSchema(pointer, schema, v, document)) { - SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_); - new (schemaMap_.template Push()) SchemaEntry(pointer, s, true, allocator_); - if (schema) - *schema = s; - } - } - } - - bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) { - static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' }; - static const ValueType kRefValue(kRefString, 4); - - typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue); - if (itr == v.MemberEnd()) - return false; - - if (itr->value.IsString()) { - SizeType len = itr->value.GetStringLength(); - if (len > 0) { - const Ch* s = itr->value.GetString(); - SizeType i = 0; - while (i < len && s[i] != '#') // Find the first # - i++; - - if (i > 0) { // Remote reference, resolve immediately - if (remoteProvider_) { - if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) { - PointerType pointer(&s[i], len - i, allocator_); - if (pointer.IsValid()) { - if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { - if (schema) - *schema = sc; - return true; - } - } - } - } - } - else if (s[i] == '#') { // Local reference, defer resolution - PointerType pointer(&s[i], len - i, allocator_); - if (pointer.IsValid()) { - if (const ValueType* nv = pointer.Get(document)) - if (HandleRefSchema(source, schema, *nv, document)) - return true; - - new (schemaRef_.template Push()) SchemaRefEntry(source, pointer, schema, allocator_); - return true; - } - } - } - } - return false; - } - - const SchemaType* GetSchema(const PointerType& pointer) const { - for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) - if (pointer == target->pointer) - return target->schema; - return 0; - } - - PointerType GetPointer(const SchemaType* schema) const { - for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) - if (schema == target->schema) - return target->pointer; - return PointerType(); - } - - static const size_t kInitialSchemaMapSize = 64; - static const size_t kInitialSchemaRefSize = 64; - - IRemoteSchemaDocumentProviderType* remoteProvider_; - Allocator *allocator_; - Allocator *ownAllocator_; - const SchemaType* root_; //!< Root schema. - internal::Stack schemaMap_; // Stores created Pointer -> Schemas - internal::Stack schemaRef_; // Stores Pointer from $ref and schema which holds the $ref -}; - -//! GenericSchemaDocument using Value type. -typedef GenericSchemaDocument SchemaDocument; -//! IGenericRemoteSchemaDocumentProvider using SchemaDocument. -typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; - -/////////////////////////////////////////////////////////////////////////////// -// GenericSchemaValidator - -//! JSON Schema Validator. -/*! - A SAX style JSON schema validator. - It uses a \c GenericSchemaDocument to validate SAX events. - It delegates the incoming SAX events to an output handler. - The default output handler does nothing. - It can be reused multiple times by calling \c Reset(). - - \tparam SchemaDocumentType Type of schema document. - \tparam OutputHandler Type of output handler. Default handler does nothing. - \tparam StateAllocator Allocator for storing the internal validation states. -*/ -template < - typename SchemaDocumentType, - typename OutputHandler = BaseReaderHandler, - typename StateAllocator = CrtAllocator> -class GenericSchemaValidator : - public internal::ISchemaStateFactory, - public internal::ISchemaValidator -{ -public: - typedef typename SchemaDocumentType::SchemaType SchemaType; - typedef typename SchemaDocumentType::PointerType PointerType; - typedef typename SchemaType::EncodingType EncodingType; - typedef typename EncodingType::Ch Ch; - - //! Constructor without output handler. - /*! - \param schemaDocument The schema document to conform to. - \param allocator Optional allocator for storing internal validation states. - \param schemaStackCapacity Optional initial capacity of schema path stack. - \param documentStackCapacity Optional initial capacity of document path stack. - */ - GenericSchemaValidator( - const SchemaDocumentType& schemaDocument, - StateAllocator* allocator = 0, - size_t schemaStackCapacity = kDefaultSchemaStackCapacity, - size_t documentStackCapacity = kDefaultDocumentStackCapacity) - : - schemaDocument_(&schemaDocument), - root_(schemaDocument.GetRoot()), - outputHandler_(GetNullHandler()), - stateAllocator_(allocator), - ownStateAllocator_(0), - schemaStack_(allocator, schemaStackCapacity), - documentStack_(allocator, documentStackCapacity), - valid_(true) -#if RAPIDJSON_SCHEMA_VERBOSE - , depth_(0) -#endif - { - } - - //! Constructor with output handler. - /*! - \param schemaDocument The schema document to conform to. - \param allocator Optional allocator for storing internal validation states. - \param schemaStackCapacity Optional initial capacity of schema path stack. - \param documentStackCapacity Optional initial capacity of document path stack. - */ - GenericSchemaValidator( - const SchemaDocumentType& schemaDocument, - OutputHandler& outputHandler, - StateAllocator* allocator = 0, - size_t schemaStackCapacity = kDefaultSchemaStackCapacity, - size_t documentStackCapacity = kDefaultDocumentStackCapacity) - : - schemaDocument_(&schemaDocument), - root_(schemaDocument.GetRoot()), - outputHandler_(outputHandler), - stateAllocator_(allocator), - ownStateAllocator_(0), - schemaStack_(allocator, schemaStackCapacity), - documentStack_(allocator, documentStackCapacity), - valid_(true) -#if RAPIDJSON_SCHEMA_VERBOSE - , depth_(0) -#endif - { - } - - //! Destructor. - ~GenericSchemaValidator() { - Reset(); - RAPIDJSON_DELETE(ownStateAllocator_); - } - - //! Reset the internal states. - void Reset() { - while (!schemaStack_.Empty()) - PopSchema(); - documentStack_.Clear(); - valid_ = true; - } - - //! Checks whether the current state is valid. - // Implementation of ISchemaValidator - virtual bool IsValid() const { return valid_; } - - //! Gets the JSON pointer pointed to the invalid schema. - PointerType GetInvalidSchemaPointer() const { - return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema()); - } - - //! Gets the keyword of invalid schema. - const Ch* GetInvalidSchemaKeyword() const { - return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword; - } - - //! Gets the JSON pointer pointed to the invalid value. - PointerType GetInvalidDocumentPointer() const { - return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); - } - -#if RAPIDJSON_SCHEMA_VERBOSE -#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ -RAPIDJSON_MULTILINEMACRO_BEGIN\ - *documentStack_.template Push() = '\0';\ - documentStack_.template Pop(1);\ - internal::PrintInvalidDocument(documentStack_.template Bottom());\ -RAPIDJSON_MULTILINEMACRO_END -#else -#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() -#endif - -#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ - if (!valid_) return false; \ - if (!BeginValue() || !CurrentSchema().method arg1) {\ - RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ - return valid_ = false;\ - } - -#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ - for (Context* context = schemaStack_.template Bottom(); context != schemaStack_.template End(); context++) {\ - if (context->hasher)\ - static_cast(context->hasher)->method arg2;\ - if (context->validators)\ - for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ - static_cast(context->validators[i_])->method arg2;\ - if (context->patternPropertiesValidators)\ - for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ - static_cast(context->patternPropertiesValidators[i_])->method arg2;\ - } - -#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ - return valid_ = EndValue() && outputHandler_.method arg2 - -#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ - RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ - RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) - - bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); } - bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } - bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } - bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } - bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } - bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } - bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } - bool RawNumber(const Ch* str, SizeType length, bool copy) - { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } - bool String(const Ch* str, SizeType length, bool copy) - { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } - - bool StartObject() { - RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); - return valid_ = outputHandler_.StartObject(); - } - - bool Key(const Ch* str, SizeType len, bool copy) { - if (!valid_) return false; - AppendToken(str, len); - if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false; - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); - return valid_ = outputHandler_.Key(str, len, copy); - } - - bool EndObject(SizeType memberCount) { - if (!valid_) return false; - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); - if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false; - RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); - } - - bool StartArray() { - RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); - return valid_ = outputHandler_.StartArray(); - } - - bool EndArray(SizeType elementCount) { - if (!valid_) return false; - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); - if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false; - RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); - } - -#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ -#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ -#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ -#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ - - // Implementation of ISchemaStateFactory - virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) { - return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, -#if RAPIDJSON_SCHEMA_VERBOSE - depth_ + 1, -#endif - &GetStateAllocator()); - } - - virtual void DestroySchemaValidator(ISchemaValidator* validator) { - GenericSchemaValidator* v = static_cast(validator); - v->~GenericSchemaValidator(); - StateAllocator::Free(v); - } - - virtual void* CreateHasher() { - return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); - } - - virtual uint64_t GetHashCode(void* hasher) { - return static_cast(hasher)->GetHashCode(); - } - - virtual void DestroryHasher(void* hasher) { - HasherType* h = static_cast(hasher); - h->~HasherType(); - StateAllocator::Free(h); - } - - virtual void* MallocState(size_t size) { - return GetStateAllocator().Malloc(size); - } - - virtual void FreeState(void* p) { - return StateAllocator::Free(p); - } - -private: - typedef typename SchemaType::Context Context; - typedef GenericValue, StateAllocator> HashCodeArray; - typedef internal::Hasher HasherType; - - GenericSchemaValidator( - const SchemaDocumentType& schemaDocument, - const SchemaType& root, -#if RAPIDJSON_SCHEMA_VERBOSE - unsigned depth, -#endif - StateAllocator* allocator = 0, - size_t schemaStackCapacity = kDefaultSchemaStackCapacity, - size_t documentStackCapacity = kDefaultDocumentStackCapacity) - : - schemaDocument_(&schemaDocument), - root_(root), - outputHandler_(GetNullHandler()), - stateAllocator_(allocator), - ownStateAllocator_(0), - schemaStack_(allocator, schemaStackCapacity), - documentStack_(allocator, documentStackCapacity), - valid_(true) -#if RAPIDJSON_SCHEMA_VERBOSE - , depth_(depth) -#endif - { - } - - StateAllocator& GetStateAllocator() { - if (!stateAllocator_) - stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator()); - return *stateAllocator_; - } - - bool BeginValue() { - if (schemaStack_.Empty()) - PushSchema(root_); - else { - if (CurrentContext().inArray) - internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); - - if (!CurrentSchema().BeginValue(CurrentContext())) - return false; - - SizeType count = CurrentContext().patternPropertiesSchemaCount; - const SchemaType** sa = CurrentContext().patternPropertiesSchemas; - typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; - bool valueUniqueness = CurrentContext().valueUniqueness; - if (CurrentContext().valueSchema) - PushSchema(*CurrentContext().valueSchema); - - if (count > 0) { - CurrentContext().objectPatternValidatorType = patternValidatorType; - ISchemaValidator**& va = CurrentContext().patternPropertiesValidators; - SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount; - va = static_cast(MallocState(sizeof(ISchemaValidator*) * count)); - for (SizeType i = 0; i < count; i++) - va[validatorCount++] = CreateSchemaValidator(*sa[i]); - } - - CurrentContext().arrayUniqueness = valueUniqueness; - } - return true; - } - - bool EndValue() { - if (!CurrentSchema().EndValue(CurrentContext())) - return false; - -#if RAPIDJSON_SCHEMA_VERBOSE - GenericStringBuffer sb; - schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb); - - *documentStack_.template Push() = '\0'; - documentStack_.template Pop(1); - internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom()); -#endif - - uint64_t h = CurrentContext().arrayUniqueness ? static_cast(CurrentContext().hasher)->GetHashCode() : 0; - - PopSchema(); - - if (!schemaStack_.Empty()) { - Context& context = CurrentContext(); - if (context.valueUniqueness) { - HashCodeArray* a = static_cast(context.arrayElementHashCodes); - if (!a) - CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); - for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) - if (itr->GetUint64() == h) - RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString()); - a->PushBack(h, GetStateAllocator()); - } - } - - // Remove the last token of document pointer - while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/') - ; - - return true; - } - - void AppendToken(const Ch* str, SizeType len) { - documentStack_.template Reserve(1 + len * 2); // worst case all characters are escaped as two characters - *documentStack_.template PushUnsafe() = '/'; - for (SizeType i = 0; i < len; i++) { - if (str[i] == '~') { - *documentStack_.template PushUnsafe() = '~'; - *documentStack_.template PushUnsafe() = '0'; - } - else if (str[i] == '/') { - *documentStack_.template PushUnsafe() = '~'; - *documentStack_.template PushUnsafe() = '1'; - } - else - *documentStack_.template PushUnsafe() = str[i]; - } - } - - RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, &schema); } - - RAPIDJSON_FORCEINLINE void PopSchema() { - Context* c = schemaStack_.template Pop(1); - if (HashCodeArray* a = static_cast(c->arrayElementHashCodes)) { - a->~HashCodeArray(); - StateAllocator::Free(a); - } - c->~Context(); - } - - const SchemaType& CurrentSchema() const { return *schemaStack_.template Top()->schema; } - Context& CurrentContext() { return *schemaStack_.template Top(); } - const Context& CurrentContext() const { return *schemaStack_.template Top(); } - - static OutputHandler& GetNullHandler() { - static OutputHandler nullHandler; - return nullHandler; - } - - static const size_t kDefaultSchemaStackCapacity = 1024; - static const size_t kDefaultDocumentStackCapacity = 256; - const SchemaDocumentType* schemaDocument_; - const SchemaType& root_; - OutputHandler& outputHandler_; - StateAllocator* stateAllocator_; - StateAllocator* ownStateAllocator_; - internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) - internal::Stack documentStack_; //!< stack to store the current path of validating document (Ch) - bool valid_; -#if RAPIDJSON_SCHEMA_VERBOSE - unsigned depth_; -#endif -}; - -typedef GenericSchemaValidator SchemaValidator; - -/////////////////////////////////////////////////////////////////////////////// -// SchemaValidatingReader - -//! A helper class for parsing with validation. -/*! - This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate(). - - \tparam parseFlags Combination of \ref ParseFlag. - \tparam InputStream Type of input stream, implementing Stream concept. - \tparam SourceEncoding Encoding of the input stream. - \tparam SchemaDocumentType Type of schema document. - \tparam StackAllocator Allocator type for stack. -*/ -template < - unsigned parseFlags, - typename InputStream, - typename SourceEncoding, - typename SchemaDocumentType = SchemaDocument, - typename StackAllocator = CrtAllocator> -class SchemaValidatingReader { -public: - typedef typename SchemaDocumentType::PointerType PointerType; - typedef typename InputStream::Ch Ch; - - //! Constructor - /*! - \param is Input stream. - \param sd Schema document. - */ - SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {} - - template - bool operator()(Handler& handler) { - GenericReader reader; - GenericSchemaValidator validator(sd_, handler); - parseResult_ = reader.template Parse(is_, validator); - - isValid_ = validator.IsValid(); - if (isValid_) { - invalidSchemaPointer_ = PointerType(); - invalidSchemaKeyword_ = 0; - invalidDocumentPointer_ = PointerType(); - } - else { - invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); - invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); - invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); - } - - return parseResult_; - } - - const ParseResult& GetParseResult() const { return parseResult_; } - bool IsValid() const { return isValid_; } - const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } - const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } - const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } - -private: - InputStream& is_; - const SchemaDocumentType& sd_; - - ParseResult parseResult_; - PointerType invalidSchemaPointer_; - const Ch* invalidSchemaKeyword_; - PointerType invalidDocumentPointer_; - bool isValid_; -}; - -RAPIDJSON_NAMESPACE_END -RAPIDJSON_DIAG_POP - -#endif // RAPIDJSON_SCHEMA_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/stream.h b/src/Native/libcryptonight/3rdparty/rapidjson/stream.h deleted file mode 100644 index fef82c252..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/stream.h +++ /dev/null @@ -1,179 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#include "rapidjson.h" - -#ifndef RAPIDJSON_STREAM_H_ -#define RAPIDJSON_STREAM_H_ - -#include "encodings.h" - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// Stream - -/*! \class rapidjson::Stream - \brief Concept for reading and writing characters. - - For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). - - For write-only stream, only need to implement Put() and Flush(). - -\code -concept Stream { - typename Ch; //!< Character type of the stream. - - //! Read the current character from stream without moving the read cursor. - Ch Peek() const; - - //! Read the current character from stream and moving the read cursor to next character. - Ch Take(); - - //! Get the current read cursor. - //! \return Number of characters read from start. - size_t Tell(); - - //! Begin writing operation at the current read pointer. - //! \return The begin writer pointer. - Ch* PutBegin(); - - //! Write a character. - void Put(Ch c); - - //! Flush the buffer. - void Flush(); - - //! End the writing operation. - //! \param begin The begin write pointer returned by PutBegin(). - //! \return Number of characters written. - size_t PutEnd(Ch* begin); -} -\endcode -*/ - -//! Provides additional information for stream. -/*! - By using traits pattern, this type provides a default configuration for stream. - For custom stream, this type can be specialized for other configuration. - See TEST(Reader, CustomStringStream) in readertest.cpp for example. -*/ -template -struct StreamTraits { - //! Whether to make local copy of stream for optimization during parsing. - /*! - By default, for safety, streams do not use local copy optimization. - Stream that can be copied fast should specialize this, like StreamTraits. - */ - enum { copyOptimization = 0 }; -}; - -//! Reserve n characters for writing to a stream. -template -inline void PutReserve(Stream& stream, size_t count) { - (void)stream; - (void)count; -} - -//! Write character to a stream, presuming buffer is reserved. -template -inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { - stream.Put(c); -} - -//! Put N copies of a character to a stream. -template -inline void PutN(Stream& stream, Ch c, size_t n) { - PutReserve(stream, n); - for (size_t i = 0; i < n; i++) - PutUnsafe(stream, c); -} - -/////////////////////////////////////////////////////////////////////////////// -// StringStream - -//! Read-only string stream. -/*! \note implements Stream concept -*/ -template -struct GenericStringStream { - typedef typename Encoding::Ch Ch; - - GenericStringStream(const Ch *src) : src_(src), head_(src) {} - - Ch Peek() const { return *src_; } - Ch Take() { return *src_++; } - size_t Tell() const { return static_cast(src_ - head_); } - - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - - const Ch* src_; //!< Current read position. - const Ch* head_; //!< Original head of the string. -}; - -template -struct StreamTraits > { - enum { copyOptimization = 1 }; -}; - -//! String stream with UTF8 encoding. -typedef GenericStringStream > StringStream; - -/////////////////////////////////////////////////////////////////////////////// -// InsituStringStream - -//! A read-write string stream. -/*! This string stream is particularly designed for in-situ parsing. - \note implements Stream concept -*/ -template -struct GenericInsituStringStream { - typedef typename Encoding::Ch Ch; - - GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} - - // Read - Ch Peek() { return *src_; } - Ch Take() { return *src_++; } - size_t Tell() { return static_cast(src_ - head_); } - - // Write - void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } - - Ch* PutBegin() { return dst_ = src_; } - size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } - void Flush() {} - - Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } - void Pop(size_t count) { dst_ -= count; } - - Ch* src_; - Ch* dst_; - Ch* head_; -}; - -template -struct StreamTraits > { - enum { copyOptimization = 1 }; -}; - -//! Insitu string stream with UTF8 encoding. -typedef GenericInsituStringStream > InsituStringStream; - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_STREAM_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/stringbuffer.h b/src/Native/libcryptonight/3rdparty/rapidjson/stringbuffer.h deleted file mode 100644 index 78f34d209..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/stringbuffer.h +++ /dev/null @@ -1,117 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_STRINGBUFFER_H_ -#define RAPIDJSON_STRINGBUFFER_H_ - -#include "stream.h" -#include "internal/stack.h" - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS -#include // std::move -#endif - -#include "internal/stack.h" - -#if defined(__clang__) -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(c++98-compat) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Represents an in-memory output stream. -/*! - \tparam Encoding Encoding of the stream. - \tparam Allocator type for allocating memory buffer. - \note implements Stream concept -*/ -template -class GenericStringBuffer { -public: - typedef typename Encoding::Ch Ch; - - GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} - GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { - if (&rhs != this) - stack_ = std::move(rhs.stack_); - return *this; - } -#endif - - void Put(Ch c) { *stack_.template Push() = c; } - void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } - void Flush() {} - - void Clear() { stack_.Clear(); } - void ShrinkToFit() { - // Push and pop a null terminator. This is safe. - *stack_.template Push() = '\0'; - stack_.ShrinkToFit(); - stack_.template Pop(1); - } - - void Reserve(size_t count) { stack_.template Reserve(count); } - Ch* Push(size_t count) { return stack_.template Push(count); } - Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } - void Pop(size_t count) { stack_.template Pop(count); } - - const Ch* GetString() const { - // Push and pop a null terminator. This is safe. - *stack_.template Push() = '\0'; - stack_.template Pop(1); - - return stack_.template Bottom(); - } - - size_t GetSize() const { return stack_.GetSize(); } - - static const size_t kDefaultCapacity = 256; - mutable internal::Stack stack_; - -private: - // Prohibit copy constructor & assignment operator. - GenericStringBuffer(const GenericStringBuffer&); - GenericStringBuffer& operator=(const GenericStringBuffer&); -}; - -//! String buffer with UTF8 encoding -typedef GenericStringBuffer > StringBuffer; - -template -inline void PutReserve(GenericStringBuffer& stream, size_t count) { - stream.Reserve(count); -} - -template -inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { - stream.PutUnsafe(c); -} - -//! Implement specialized version of PutN() with memset() for better performance. -template<> -inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { - std::memset(stream.stack_.Push(n), c, n * sizeof(c)); -} - -RAPIDJSON_NAMESPACE_END - -#if defined(__clang__) -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_STRINGBUFFER_H_ diff --git a/src/Native/libcryptonight/3rdparty/rapidjson/writer.h b/src/Native/libcryptonight/3rdparty/rapidjson/writer.h deleted file mode 100644 index 94f22dd5f..000000000 --- a/src/Native/libcryptonight/3rdparty/rapidjson/writer.h +++ /dev/null @@ -1,610 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_WRITER_H_ -#define RAPIDJSON_WRITER_H_ - -#include "stream.h" -#include "internal/stack.h" -#include "internal/strfunc.h" -#include "internal/dtoa.h" -#include "internal/itoa.h" -#include "stringbuffer.h" -#include // placement new - -#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) -#include -#pragma intrinsic(_BitScanForward) -#endif -#ifdef RAPIDJSON_SSE42 -#include -#elif defined(RAPIDJSON_SSE2) -#include -#endif - -#ifdef _MSC_VER -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -RAPIDJSON_DIAG_OFF(unreachable-code) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// WriteFlag - -/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS - \ingroup RAPIDJSON_CONFIG - \brief User-defined kWriteDefaultFlags definition. - - User can define this as any \c WriteFlag combinations. -*/ -#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS -#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags -#endif - -//! Combination of writeFlags -enum WriteFlag { - kWriteNoFlags = 0, //!< No flags are set. - kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. - kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. - kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS -}; - -//! JSON writer -/*! Writer implements the concept Handler. - It generates JSON text by events to an output os. - - User may programmatically calls the functions of a writer to generate JSON text. - - On the other side, a writer can also be passed to objects that generates events, - - for example Reader::Parse() and Document::Accept(). - - \tparam OutputStream Type of output stream. - \tparam SourceEncoding Encoding of source string. - \tparam TargetEncoding Encoding of output stream. - \tparam StackAllocator Type of allocator for allocating memory of stack. - \note implements Handler concept -*/ -template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> -class Writer { -public: - typedef typename SourceEncoding::Ch Ch; - - static const int kDefaultMaxDecimalPlaces = 324; - - //! Constructor - /*! \param os Output stream. - \param stackAllocator User supplied allocator. If it is null, it will create a private one. - \param levelDepth Initial capacity of stack. - */ - explicit - Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : - os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} - - explicit - Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : - os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} - - //! Reset the writer with a new stream. - /*! - This function reset the writer with a new stream and default settings, - in order to make a Writer object reusable for output multiple JSONs. - - \param os New output stream. - \code - Writer writer(os1); - writer.StartObject(); - // ... - writer.EndObject(); - - writer.Reset(os2); - writer.StartObject(); - // ... - writer.EndObject(); - \endcode - */ - void Reset(OutputStream& os) { - os_ = &os; - hasRoot_ = false; - level_stack_.Clear(); - } - - //! Checks whether the output is a complete JSON. - /*! - A complete JSON has a complete root object or array. - */ - bool IsComplete() const { - return hasRoot_ && level_stack_.Empty(); - } - - int GetMaxDecimalPlaces() const { - return maxDecimalPlaces_; - } - - //! Sets the maximum number of decimal places for double output. - /*! - This setting truncates the output with specified number of decimal places. - - For example, - - \code - writer.SetMaxDecimalPlaces(3); - writer.StartArray(); - writer.Double(0.12345); // "0.123" - writer.Double(0.0001); // "0.0" - writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent) - writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent) - writer.EndArray(); - \endcode - - The default setting does not truncate any decimal places. You can restore to this setting by calling - \code - writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces); - \endcode - */ - void SetMaxDecimalPlaces(int maxDecimalPlaces) { - maxDecimalPlaces_ = maxDecimalPlaces; - } - - /*!@name Implementation of Handler - \see Handler - */ - //@{ - - bool Null() { Prefix(kNullType); return EndValue(WriteNull()); } - bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); } - bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); } - bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); } - bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); } - bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); } - - //! Writes the given \c double value to the stream - /*! - \param d The value to be written. - \return Whether it is succeed. - */ - bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); } - - bool RawNumber(const Ch* str, SizeType length, bool copy = false) { - (void)copy; - Prefix(kNumberType); - return EndValue(WriteString(str, length)); - } - - bool String(const Ch* str, SizeType length, bool copy = false) { - (void)copy; - Prefix(kStringType); - return EndValue(WriteString(str, length)); - } - -#if RAPIDJSON_HAS_STDSTRING - bool String(const std::basic_string& str) { - return String(str.data(), SizeType(str.size())); - } -#endif - - bool StartObject() { - Prefix(kObjectType); - new (level_stack_.template Push()) Level(false); - return WriteStartObject(); - } - - bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } - - bool EndObject(SizeType memberCount = 0) { - (void)memberCount; - RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); - RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); - level_stack_.template Pop(1); - return EndValue(WriteEndObject()); - } - - bool StartArray() { - Prefix(kArrayType); - new (level_stack_.template Push()) Level(true); - return WriteStartArray(); - } - - bool EndArray(SizeType elementCount = 0) { - (void)elementCount; - RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); - RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); - level_stack_.template Pop(1); - return EndValue(WriteEndArray()); - } - //@} - - /*! @name Convenience extensions */ - //@{ - - //! Simpler but slower overload. - bool String(const Ch* str) { return String(str, internal::StrLen(str)); } - bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } - - //@} - - //! Write a raw JSON value. - /*! - For user to write a stringified JSON as a value. - - \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. - \param length Length of the json. - \param type Type of the root of json. - */ - bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return EndValue(WriteRawValue(json, length)); } - -protected: - //! Information for each nested level - struct Level { - Level(bool inArray_) : valueCount(0), inArray(inArray_) {} - size_t valueCount; //!< number of values in this level - bool inArray; //!< true if in array, otherwise in object - }; - - static const size_t kDefaultLevelDepth = 32; - - bool WriteNull() { - PutReserve(*os_, 4); - PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; - } - - bool WriteBool(bool b) { - if (b) { - PutReserve(*os_, 4); - PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); - } - else { - PutReserve(*os_, 5); - PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); - } - return true; - } - - bool WriteInt(int i) { - char buffer[11]; - const char* end = internal::i32toa(i, buffer); - PutReserve(*os_, static_cast(end - buffer)); - for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteUint(unsigned u) { - char buffer[10]; - const char* end = internal::u32toa(u, buffer); - PutReserve(*os_, static_cast(end - buffer)); - for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteInt64(int64_t i64) { - char buffer[21]; - const char* end = internal::i64toa(i64, buffer); - PutReserve(*os_, static_cast(end - buffer)); - for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteUint64(uint64_t u64) { - char buffer[20]; - char* end = internal::u64toa(u64, buffer); - PutReserve(*os_, static_cast(end - buffer)); - for (char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteDouble(double d) { - if (internal::Double(d).IsNanOrInf()) { - if (!(writeFlags & kWriteNanAndInfFlag)) - return false; - if (internal::Double(d).IsNan()) { - PutReserve(*os_, 3); - PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); - return true; - } - if (internal::Double(d).Sign()) { - PutReserve(*os_, 9); - PutUnsafe(*os_, '-'); - } - else - PutReserve(*os_, 8); - PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); - PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); - return true; - } - - char buffer[25]; - char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); - PutReserve(*os_, static_cast(end - buffer)); - for (char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); - return true; - } - - bool WriteString(const Ch* str, SizeType length) { - static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - static const char escape[256] = { -#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - //0 1 2 3 4 5 6 7 8 9 A B C D E F - 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 - 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 - 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 - Z16, Z16, // 30~4F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 - Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF -#undef Z16 - }; - - if (TargetEncoding::supportUnicode) - PutReserve(*os_, 2 + length * 6); // "\uxxxx..." - else - PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." - - PutUnsafe(*os_, '\"'); - GenericStringStream is(str); - while (ScanWriteUnescapedString(is, length)) { - const Ch c = is.Peek(); - if (!TargetEncoding::supportUnicode && static_cast(c) >= 0x80) { - // Unicode escaping - unsigned codepoint; - if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) - return false; - PutUnsafe(*os_, '\\'); - PutUnsafe(*os_, 'u'); - if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { - PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); - PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); - PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); - PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); - } - else { - RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); - // Surrogate pair - unsigned s = codepoint - 0x010000; - unsigned lead = (s >> 10) + 0xD800; - unsigned trail = (s & 0x3FF) + 0xDC00; - PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); - PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); - PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); - PutUnsafe(*os_, hexDigits[(lead ) & 15]); - PutUnsafe(*os_, '\\'); - PutUnsafe(*os_, 'u'); - PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); - PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); - PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); - PutUnsafe(*os_, hexDigits[(trail ) & 15]); - } - } - else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast(c)])) { - is.Take(); - PutUnsafe(*os_, '\\'); - PutUnsafe(*os_, static_cast(escape[static_cast(c)])); - if (escape[static_cast(c)] == 'u') { - PutUnsafe(*os_, '0'); - PutUnsafe(*os_, '0'); - PutUnsafe(*os_, hexDigits[static_cast(c) >> 4]); - PutUnsafe(*os_, hexDigits[static_cast(c) & 0xF]); - } - } - else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? - Transcoder::Validate(is, *os_) : - Transcoder::TranscodeUnsafe(is, *os_)))) - return false; - } - PutUnsafe(*os_, '\"'); - return true; - } - - bool ScanWriteUnescapedString(GenericStringStream& is, size_t length) { - return RAPIDJSON_LIKELY(is.Tell() < length); - } - - bool WriteStartObject() { os_->Put('{'); return true; } - bool WriteEndObject() { os_->Put('}'); return true; } - bool WriteStartArray() { os_->Put('['); return true; } - bool WriteEndArray() { os_->Put(']'); return true; } - - bool WriteRawValue(const Ch* json, size_t length) { - PutReserve(*os_, length); - for (size_t i = 0; i < length; i++) { - RAPIDJSON_ASSERT(json[i] != '\0'); - PutUnsafe(*os_, json[i]); - } - return true; - } - - void Prefix(Type type) { - (void)type; - if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root - Level* level = level_stack_.template Top(); - if (level->valueCount > 0) { - if (level->inArray) - os_->Put(','); // add comma if it is not the first element in array - else // in object - os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); - } - if (!level->inArray && level->valueCount % 2 == 0) - RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name - level->valueCount++; - } - else { - RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. - hasRoot_ = true; - } - } - - // Flush the value if it is the top level one. - bool EndValue(bool ret) { - if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text - os_->Flush(); - return ret; - } - - OutputStream* os_; - internal::Stack level_stack_; - int maxDecimalPlaces_; - bool hasRoot_; - -private: - // Prohibit copy constructor & assignment operator. - Writer(const Writer&); - Writer& operator=(const Writer&); -}; - -// Full specialization for StringStream to prevent memory copying - -template<> -inline bool Writer::WriteInt(int i) { - char *buffer = os_->Push(11); - const char* end = internal::i32toa(i, buffer); - os_->Pop(static_cast(11 - (end - buffer))); - return true; -} - -template<> -inline bool Writer::WriteUint(unsigned u) { - char *buffer = os_->Push(10); - const char* end = internal::u32toa(u, buffer); - os_->Pop(static_cast(10 - (end - buffer))); - return true; -} - -template<> -inline bool Writer::WriteInt64(int64_t i64) { - char *buffer = os_->Push(21); - const char* end = internal::i64toa(i64, buffer); - os_->Pop(static_cast(21 - (end - buffer))); - return true; -} - -template<> -inline bool Writer::WriteUint64(uint64_t u) { - char *buffer = os_->Push(20); - const char* end = internal::u64toa(u, buffer); - os_->Pop(static_cast(20 - (end - buffer))); - return true; -} - -template<> -inline bool Writer::WriteDouble(double d) { - if (internal::Double(d).IsNanOrInf()) { - // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). - if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) - return false; - if (internal::Double(d).IsNan()) { - PutReserve(*os_, 3); - PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); - return true; - } - if (internal::Double(d).Sign()) { - PutReserve(*os_, 9); - PutUnsafe(*os_, '-'); - } - else - PutReserve(*os_, 8); - PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); - PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); - return true; - } - - char *buffer = os_->Push(25); - char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); - os_->Pop(static_cast(25 - (end - buffer))); - return true; -} - -#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) -template<> -inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { - if (length < 16) - return RAPIDJSON_LIKELY(is.Tell() < length); - - if (!RAPIDJSON_LIKELY(is.Tell() < length)) - return false; - - const char* p = is.src_; - const char* end = is.head_ + length; - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); - if (nextAligned > end) - return true; - - while (p != nextAligned) - if (*p < 0x20 || *p == '\"' || *p == '\\') { - is.src_ = p; - return RAPIDJSON_LIKELY(is.Tell() < length); - } - else - os_->PutUnsafe(*p++); - - // The rest of string using SIMD - static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; - static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; - const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); - const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); - const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); - - for (; p != endAligned; p += 16) { - const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const __m128i t1 = _mm_cmpeq_epi8(s, dq); - const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 - const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); - unsigned short r = static_cast(_mm_movemask_epi8(x)); - if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped - SizeType len; -#ifdef _MSC_VER // Find the index of first escaped - unsigned long offset; - _BitScanForward(&offset, r); - len = offset; -#else - len = static_cast(__builtin_ffs(r) - 1); -#endif - char* q = reinterpret_cast(os_->PushUnsafe(len)); - for (size_t i = 0; i < len; i++) - q[i] = p[i]; - - p += len; - break; - } - _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); - } - - is.src_ = p; - return RAPIDJSON_LIKELY(is.Tell() < length); -} -#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) - -RAPIDJSON_NAMESPACE_END - -#ifdef _MSC_VER -RAPIDJSON_DIAG_POP -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/src/Native/libcryptonight/Makefile b/src/Native/libcryptonight/Makefile index 79dc5427c..3b6aa70cf 100644 --- a/src/Native/libcryptonight/Makefile +++ b/src/Native/libcryptonight/Makefile @@ -1,5 +1,5 @@ CC = gcc -INC_DIRS = -I. -I./3rdparty +INC_DIRS = -Ixmrig -IIxmrig/3rdparty # Temporarily disable optimizations to debug crashes CFLAGS = -g -Wall -c -fPIC -maes -O2 -fpermissive -Wno-fpermissive -Wno-strict-aliasing -Wno-sign-compare -DCPU_INTEL $(INC_DIRS) @@ -8,8 +8,13 @@ CXXFLAGS = -g -Wall -maes -O2 -Wno-unused-function -fPIC -fpermissive -Wno-stric LDFLAGS = -shared TARGET = libcryptonight.so -OBJECTS = crypto/c_blake256.c crypto/c_groestl.c crypto/c_jh.c crypto/c_skein.c common/crypto/keccak.cpp exports.o \ - crypto/Asm.cpp crypto/asm/cnv2_main_loop.S +OBJECTS = xmrig/crypto/asm/cn_main_loop.o xmrig/crypto/asm/CryptonightR_template.o \ + xmrig/crypto/cn_gpu_ssse3.o xmrig/common/cpu/Cpu.o xmrig/common/cpu/BasicCpuInfo.o \ + xmrig/extra.o xmrig/Mem.o xmrig/Mem_unix.o \ + xmrig/crypto/c_blake256.o xmrig/crypto/c_groestl.o xmrig/crypto/c_jh.o \ + xmrig/crypto/c_skein.o xmrig/common/crypto/keccak.o \ + xmrig/crypto/CryptonightR_gen.o \ + exports.o all: $(TARGET) diff --git a/src/Native/libcryptonight/common/xmrig.h b/src/Native/libcryptonight/common/xmrig.h deleted file mode 100644 index 0645a2344..000000000 --- a/src/Native/libcryptonight/common/xmrig.h +++ /dev/null @@ -1,109 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef XMRIG_XMRIG_H -#define XMRIG_XMRIG_H - - -namespace xmrig -{ - - - enum Algo { - INVALID_ALGO = -1, - CRYPTONIGHT, /* CryptoNight (Monero) */ - CRYPTONIGHT_LITE, /* CryptoNight-Lite (AEON) */ - CRYPTONIGHT_HEAVY /* CryptoNight-Heavy (RYO) */ - }; - - - //--av=1 For CPUs with hardware AES. - //--av=2 Lower power mode (double hash) of 1. - //--av=3 Software AES implementation. - //--av=4 Lower power mode (double hash) of 3. - enum AlgoVariant { - AV_AUTO, // --av=0 Automatic mode. - AV_SINGLE, // --av=1 Single hash mode - AV_DOUBLE, // --av=2 Double hash mode - AV_SINGLE_SOFT, // --av=3 Single hash mode (Software AES) - AV_DOUBLE_SOFT, // --av=4 Double hash mode (Software AES) - AV_TRIPLE, // --av=5 Triple hash mode - AV_QUAD, // --av=6 Quard hash mode - AV_PENTA, // --av=7 Penta hash mode - AV_TRIPLE_SOFT, // --av=8 Triple hash mode (Software AES) - AV_QUAD_SOFT, // --av=9 Quard hash mode (Software AES) - AV_PENTA_SOFT, // --av=10 Penta hash mode (Software AES) - AV_MAX - }; - - - enum Variant { - VARIANT_AUTO = -1, // Autodetect - VARIANT_0 = 0, // Original CryptoNight or CryptoNight-Heavy - VARIANT_1 = 1, // CryptoNight variant 1 also known as Monero7 and CryptoNightV7 - VARIANT_TUBE = 2, // Modified CryptoNight-Heavy (TUBE only) - VARIANT_XTL = 3, // Modified CryptoNight variant 1 (Stellite only) - VARIANT_MSR = 4, // Modified CryptoNight variant 1 (Masari only) - VARIANT_XHV = 5, // Modified CryptoNight-Heavy (Haven Protocol only) - VARIANT_XAO = 6, // Modified CryptoNight variant 0 (Alloy only) - VARIANT_RTO = 7, // Modified CryptoNight variant 1 (Arto only) - VARIANT_2 = 8, // CryptoNight variant 2 - VARIANT_MAX - }; - - - enum AlgoVerify { - VERIFY_HW_AES = 1, - VERIFY_SOFT_AES = 2 - }; - - - enum AesMode { - AES_AUTO, - AES_HW, - AES_SOFT - }; - - - enum OclVendor { - OCL_VENDOR_UNKNOWN = -2, - OCL_VENDOR_MANUAL = -1, - OCL_VENDOR_AMD = 0, - OCL_VENDOR_NVIDIA = 1, - OCL_VENDOR_INTEL = 2 - }; - - - enum Assembly { - ASM_NONE, - ASM_AUTO, - ASM_INTEL, - ASM_RYZEN, - ASM_MAX - }; - - -} /* namespace xmrig */ - - -#endif /* XMRIG_XMRIG_H */ diff --git a/src/Native/libcryptonight/crypto/Asm.cpp b/src/Native/libcryptonight/crypto/Asm.cpp deleted file mode 100644 index 48c1beb8e..000000000 --- a/src/Native/libcryptonight/crypto/Asm.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -#include -#include - - -#ifdef _MSC_VER -# define strncasecmp _strnicmp -# define strcasecmp _stricmp -#endif - - -#include "crypto/Asm.h" -#include "rapidjson/document.h" - - -static const char *asmNames[] = { - "none", - "auto", - "intel", - "ryzen" -}; - - -xmrig::Assembly xmrig::Asm::parse(const char *assembly, Assembly defaultValue) -{ - constexpr size_t const size = sizeof(asmNames) / sizeof((asmNames)[0]); - assert(assembly != nullptr); - assert(ASM_MAX == size); - - if (assembly == nullptr) { - return defaultValue; - } - - for (size_t i = 0; i < size; i++) { - if (strcasecmp(assembly, asmNames[i]) == 0) { - return static_cast(i); - } - } - - return defaultValue; -} - - -xmrig::Assembly xmrig::Asm::parse(const rapidjson::Value &value, Assembly defaultValue) -{ - if (value.IsBool()) { - return parse(value.GetBool()); - } - - if (value.IsString()) { - return parse(value.GetString(), defaultValue); - } - - return defaultValue; -} - - -const char *xmrig::Asm::toString(Assembly assembly) -{ - return asmNames[assembly]; -} - - -rapidjson::Value xmrig::Asm::toJSON(Assembly assembly) -{ - using namespace rapidjson; - - if (assembly == ASM_NONE) { - return Value(false); - } - - if (assembly == ASM_AUTO) { - return Value(true); - } - - return Value(StringRef(toString(assembly))); -} diff --git a/src/Native/libcryptonight/crypto/CryptoNight_test.h b/src/Native/libcryptonight/crypto/CryptoNight_test.h deleted file mode 100644 index 95e12197b..000000000 --- a/src/Native/libcryptonight/crypto/CryptoNight_test.h +++ /dev/null @@ -1,237 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018 Lee Clagett - * Copyright 2016-2018 XMRig , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __CRYPTONIGHT_TEST_H__ -#define __CRYPTONIGHT_TEST_H__ - - -const static uint8_t test_input[380] = { - 0x03, 0x05, 0xA0, 0xDB, 0xD6, 0xBF, 0x05, 0xCF, 0x16, 0xE5, 0x03, 0xF3, 0xA6, 0x6F, 0x78, 0x00, - 0x7C, 0xBF, 0x34, 0x14, 0x43, 0x32, 0xEC, 0xBF, 0xC2, 0x2E, 0xD9, 0x5C, 0x87, 0x00, 0x38, 0x3B, - 0x30, 0x9A, 0xCE, 0x19, 0x23, 0xA0, 0x96, 0x4B, 0x00, 0x00, 0x00, 0x08, 0xBA, 0x93, 0x9A, 0x62, - 0x72, 0x4C, 0x0D, 0x75, 0x81, 0xFC, 0xE5, 0x76, 0x1E, 0x9D, 0x8A, 0x0E, 0x6A, 0x1C, 0x3F, 0x92, - 0x4F, 0xDD, 0x84, 0x93, 0xD1, 0x11, 0x56, 0x49, 0xC0, 0x5E, 0xB6, 0x01, - 0x01, 0x00, 0xFB, 0x8E, 0x8A, 0xC8, 0x05, 0x89, 0x93, 0x23, 0x37, 0x1B, 0xB7, 0x90, 0xDB, 0x19, - 0x21, 0x8A, 0xFD, 0x8D, 0xB8, 0xE3, 0x75, 0x5D, 0x8B, 0x90, 0xF3, 0x9B, 0x3D, 0x55, 0x06, 0xA9, - 0xAB, 0xCE, 0x4F, 0xA9, 0x12, 0x24, 0x45, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x81, 0x46, 0xD4, 0x9F, - 0xA9, 0x3E, 0xE7, 0x24, 0xDE, 0xB5, 0x7D, 0x12, 0xCB, 0xC6, 0xC6, 0xF3, 0xB9, 0x24, 0xD9, 0x46, - 0x12, 0x7C, 0x7A, 0x97, 0x41, 0x8F, 0x93, 0x48, 0x82, 0x8F, 0x0F, 0x02, - 0x07, 0x07, 0xB4, 0x87, 0xD0, 0xD6, 0x05, 0x26, 0xE0, 0xC6, 0xDD, 0x9B, 0xC7, 0x18, 0xC3, 0xCF, - 0x52, 0x04, 0xBD, 0x4F, 0x9B, 0x27, 0xF6, 0x73, 0xB9, 0x3F, 0xEF, 0x7B, 0xB2, 0xF7, 0x2B, 0xBB, - 0x3F, 0x3E, 0x9C, 0x3E, 0x9D, 0x33, 0x1E, 0xDE, 0xAD, 0xBE, 0xEF, 0x4E, 0x00, 0x91, 0x81, 0x29, - 0x74, 0xB2, 0x70, 0xE7, 0x6D, 0xD2, 0x2A, 0x5F, 0x52, 0x04, 0x93, 0xE6, 0x18, 0x89, 0x40, 0xD8, - 0xC6, 0xE3, 0x90, 0x6E, 0xAA, 0x6A, 0xB7, 0xE2, 0x08, 0x7E, 0x78, 0x0E, - 0x01, 0x00, 0xEE, 0xB2, 0xD1, 0xD6, 0x05, 0xFF, 0x27, 0x7F, 0x26, 0xDB, 0xAA, 0xB2, 0xC9, 0x26, - 0x30, 0xC6, 0xCF, 0x11, 0x64, 0xEA, 0x6C, 0x8A, 0xE0, 0x98, 0x01, 0xF8, 0x75, 0x4B, 0x49, 0xAF, - 0x79, 0x70, 0xAE, 0xEE, 0xA7, 0x62, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x47, 0x8C, 0x63, 0xE7, 0xD8, - 0x40, 0x02, 0x3C, 0xDA, 0xEA, 0x92, 0x52, 0x53, 0xAC, 0xFD, 0xC7, 0x8A, 0x4C, 0x31, 0xB2, 0xF2, - 0xEC, 0x72, 0x7B, 0xFF, 0xCE, 0xC0, 0xE7, 0x12, 0xD4, 0xE9, 0x2A, 0x01, - 0x07, 0x07, 0xA9, 0xB7, 0xD1, 0xD6, 0x05, 0x3F, 0x0D, 0x5E, 0xFD, 0xC7, 0x03, 0xFC, 0xFC, 0xD2, - 0xCE, 0xBC, 0x44, 0xD8, 0xAB, 0x44, 0xA6, 0xA0, 0x3A, 0xE4, 0x4D, 0x8F, 0x15, 0xAF, 0x62, 0x17, - 0xD1, 0xE0, 0x92, 0x85, 0xE4, 0x73, 0xF9, 0x00, 0x00, 0x00, 0xA0, 0xFC, 0x09, 0xDE, 0xAB, 0xF5, - 0x8B, 0x6F, 0x1D, 0xCA, 0xA8, 0xBA, 0xAC, 0x74, 0xDD, 0x74, 0x19, 0xD5, 0xD6, 0x10, 0xEC, 0x38, - 0xCF, 0x50, 0x29, 0x6A, 0x07, 0x0B, 0x93, 0x8F, 0x8F, 0xA8, 0x10, 0x04 -}; - - -const static uint8_t test_output_v0[160] = { - 0x1A, 0x3F, 0xFB, 0xEE, 0x90, 0x9B, 0x42, 0x0D, 0x91, 0xF7, 0xBE, 0x6E, 0x5F, 0xB5, 0x6D, 0xB7, - 0x1B, 0x31, 0x10, 0xD8, 0x86, 0x01, 0x1E, 0x87, 0x7E, 0xE5, 0x78, 0x6A, 0xFD, 0x08, 0x01, 0x00, - 0x1B, 0x60, 0x6A, 0x3F, 0x4A, 0x07, 0xD6, 0x48, 0x9A, 0x1B, 0xCD, 0x07, 0x69, 0x7B, 0xD1, 0x66, - 0x96, 0xB6, 0x1C, 0x8A, 0xE9, 0x82, 0xF6, 0x1A, 0x90, 0x16, 0x0F, 0x4E, 0x52, 0x82, 0x8A, 0x7F, - 0xA1, 0xB4, 0xFA, 0xE3, 0xE5, 0x76, 0xCE, 0xCF, 0xB7, 0x9C, 0xAF, 0x3E, 0x29, 0x92, 0xE4, 0xE0, - 0x31, 0x24, 0x05, 0x48, 0xBF, 0x8D, 0x5F, 0x7B, 0x11, 0x03, 0x60, 0xAA, 0xD7, 0x50, 0x3F, 0x0C, - 0x2D, 0x30, 0xF3, 0x87, 0x4F, 0x86, 0xA1, 0x4A, 0xB5, 0xA2, 0x1A, 0x08, 0xD0, 0x44, 0x2C, 0x9D, - 0x16, 0xE9, 0x28, 0x49, 0xA1, 0xFF, 0x85, 0x6F, 0x12, 0xBB, 0x7D, 0xAB, 0x11, 0x1C, 0xE7, 0xF7, - 0x2D, 0x9D, 0x19, 0xE4, 0xD2, 0x26, 0x44, 0x1E, 0xCD, 0x22, 0x08, 0x24, 0xA8, 0x97, 0x46, 0x62, - 0x04, 0x84, 0x90, 0x4A, 0xEE, 0x99, 0x14, 0xED, 0xB8, 0xC6, 0x0D, 0x37, 0xA1, 0x66, 0x17, 0xB0 -}; - - -// Cryptonight variant 1 (Monero v7) -const static uint8_t test_output_v1[160] = { - 0xF2, 0x2D, 0x3D, 0x62, 0x03, 0xD2, 0xA0, 0x8B, 0x41, 0xD9, 0x02, 0x72, 0x78, 0xD8, 0xBC, 0xC9, - 0x83, 0xAC, 0xAD, 0xA9, 0xB6, 0x8E, 0x52, 0xE3, 0xC6, 0x89, 0x69, 0x2A, 0x50, 0xE9, 0x21, 0xD9, - 0xC9, 0xFA, 0xE8, 0x42, 0x5D, 0x86, 0x88, 0xDC, 0x23, 0x6B, 0xCD, 0xBC, 0x42, 0xFD, 0xB4, 0x2D, - 0x37, 0x6C, 0x6E, 0xC1, 0x90, 0x50, 0x1A, 0xA8, 0x4B, 0x04, 0xA4, 0xB4, 0xCF, 0x1E, 0xE1, 0x22, - 0xE7, 0x8C, 0x5A, 0x6E, 0x38, 0x30, 0x68, 0x4A, 0x73, 0xFC, 0x1B, 0xC6, 0x6D, 0xFC, 0x8D, 0x98, - 0xB4, 0xC2, 0x23, 0x39, 0xAD, 0xE0, 0x9D, 0xF6, 0x6D, 0x8C, 0x6A, 0xAA, 0xF9, 0xB2, 0xE3, 0x4C, - 0xB6, 0x90, 0x6C, 0xE6, 0x15, 0x5E, 0x46, 0x07, 0x9C, 0xB2, 0x6B, 0xAC, 0x3B, 0xAC, 0x1A, 0xDE, - 0x92, 0x2C, 0xD6, 0x0C, 0x46, 0x9D, 0x9B, 0xC2, 0x84, 0x52, 0x65, 0xF6, 0xBD, 0xFA, 0x0D, 0x74, - 0x00, 0x66, 0x10, 0x07, 0xF1, 0x19, 0x06, 0x3A, 0x6C, 0xFF, 0xEE, 0xB2, 0x40, 0xE5, 0x88, 0x2B, - 0x6C, 0xAB, 0x6B, 0x1D, 0x88, 0xB8, 0x44, 0x25, 0xF4, 0xEA, 0xB7, 0xEC, 0xBA, 0x12, 0x8A, 0x24 -}; - - -// Cryptonight variant 2 (Monero v8) -const static uint8_t test_output_v2[160] = { - 0x97, 0x37, 0x82, 0x82, 0xCF, 0x10, 0xE7, 0xAD, 0x03, 0x3F, 0x7B, 0x80, 0x74, 0xC4, 0x0E, 0x14, - 0xD0, 0x6E, 0x7F, 0x60, 0x9D, 0xDD, 0xDA, 0x78, 0x76, 0x80, 0xB5, 0x8C, 0x05, 0xF4, 0x3D, 0x21, - 0x87, 0x1F, 0xCD, 0x68, 0x23, 0xF6, 0xA8, 0x79, 0xBB, 0x3F, 0x33, 0x95, 0x1C, 0x8E, 0x8E, 0x89, - 0x1D, 0x40, 0x43, 0x88, 0x0B, 0x02, 0xDF, 0xA1, 0xBB, 0x3B, 0xE4, 0x98, 0xB5, 0x0E, 0x75, 0x78, - 0xE6, 0x0D, 0x24, 0x0F, 0x65, 0x85, 0x60, 0x3A, 0x4A, 0xE5, 0x5F, 0x54, 0x9B, 0xC8, 0x79, 0x93, - 0xEB, 0x3D, 0x98, 0x2C, 0xFE, 0x9B, 0xFB, 0x15, 0xB6, 0x88, 0x21, 0x94, 0xB0, 0x05, 0x86, 0x5C, - 0x59, 0x8B, 0x93, 0x7A, 0xDA, 0xD2, 0xA2, 0x14, 0xED, 0xB7, 0xC4, 0x5D, 0xA1, 0xEF, 0x26, 0xF3, - 0xC7, 0x73, 0x29, 0x4D, 0xF1, 0xC8, 0x2C, 0xE0, 0xD0, 0xE9, 0xED, 0x0C, 0x70, 0x75, 0x05, 0x3E, - 0x5B, 0xF6, 0xA0, 0x6E, 0xEA, 0xDE, 0x87, 0x0B, 0x06, 0x29, 0x03, 0xBF, 0xB4, 0x85, 0x9D, 0x04, - 0x75, 0x1A, 0xCD, 0x1E, 0xD6, 0xAA, 0x1B, 0x05, 0x24, 0x6A, 0x2C, 0x80, 0x69, 0x68, 0xDC, 0x97 -}; - - -// Stellite (XTL) -const static uint8_t test_output_xtl[160] = { - 0x8F, 0xE5, 0xF0, 0x5F, 0x02, 0x2A, 0x61, 0x7D, 0xE5, 0x3F, 0x79, 0x36, 0x4B, 0x25, 0xCB, 0xC3, - 0xC0, 0x8E, 0x0E, 0x1F, 0xE3, 0xBE, 0x48, 0x57, 0x07, 0x03, 0xFE, 0xE1, 0xEC, 0x0E, 0xB0, 0xB1, - 0x21, 0x26, 0xFF, 0x98, 0xE6, 0x86, 0x08, 0x5B, 0xC9, 0x96, 0x44, 0xA3, 0xB8, 0x4E, 0x28, 0x90, - 0x76, 0xED, 0xAD, 0xB9, 0xAA, 0xAC, 0x01, 0x94, 0x1D, 0xBE, 0x3E, 0xEA, 0xAD, 0xEE, 0xB2, 0xCF, - 0xB0, 0x43, 0x4B, 0x88, 0xFC, 0xB2, 0xF3, 0x82, 0x9D, 0xD7, 0xDF, 0x51, 0x97, 0x2C, 0x5A, 0xE3, - 0xC7, 0x16, 0x0B, 0xC8, 0x7C, 0xB7, 0x2F, 0x1C, 0x55, 0x33, 0xCA, 0xE1, 0xEE, 0x08, 0xA4, 0x86, - 0x60, 0xED, 0x6E, 0x9D, 0x2D, 0x05, 0x0D, 0x7D, 0x02, 0x49, 0x23, 0x39, 0x7C, 0xC3, 0x6D, 0x3D, - 0x05, 0x51, 0x28, 0xF1, 0x9B, 0x3C, 0xDF, 0xC4, 0xEA, 0x8A, 0xA6, 0x6A, 0x3C, 0x8B, 0xE2, 0xAF, - 0x47, 0x00, 0xFC, 0x36, 0xED, 0x50, 0xBB, 0xD2, 0x2E, 0x63, 0x4B, 0x93, 0x11, 0x0C, 0xA7, 0xBA, - 0x32, 0x6E, 0x47, 0x4D, 0xCE, 0xCC, 0x82, 0x54, 0x1D, 0x06, 0xF8, 0x06, 0x86, 0xBD, 0x22, 0x48 -}; - - -// Masari (MSR) -const static uint8_t test_output_msr[160] = { - 0x3C, 0x7A, 0x61, 0x08, 0x4C, 0x5E, 0xB8, 0x65, 0xB4, 0x98, 0xAB, 0x2F, 0x5A, 0x1A, 0xC5, 0x2C, - 0x49, 0xC1, 0x77, 0xC2, 0xD0, 0x13, 0x34, 0x42, 0xD6, 0x5E, 0xD5, 0x14, 0x33, 0x5C, 0x82, 0xC5, - 0x69, 0xDF, 0x38, 0x51, 0x1B, 0xB3, 0xEB, 0x7D, 0xE7, 0x6B, 0x08, 0x8E, 0xB6, 0x7E, 0xB7, 0x1C, - 0x5F, 0x3C, 0x81, 0xC9, 0xF7, 0xCE, 0xAE, 0x28, 0xC0, 0xFE, 0xEB, 0xBA, 0x0B, 0x40, 0x38, 0x1D, - 0x44, 0xD0, 0xD5, 0xD3, 0x98, 0x1F, 0xA3, 0x0E, 0xE9, 0x89, 0x1A, 0xD7, 0x88, 0xCC, 0x25, 0x76, - 0x9C, 0xFF, 0x4D, 0x7F, 0x9C, 0xCF, 0x48, 0x07, 0x91, 0xF9, 0x82, 0xF5, 0x4C, 0xE9, 0xBD, 0x82, - 0x36, 0x36, 0x64, 0x14, 0xED, 0xB8, 0x54, 0xEE, 0x22, 0xA1, 0x66, 0xA3, 0x87, 0x10, 0x76, 0x1F, - 0x5A, 0xCD, 0x4C, 0x31, 0x4C, 0xBA, 0x41, 0xD2, 0xDB, 0x6C, 0x31, 0x2E, 0x7A, 0x64, 0x15, 0xFF, - 0xA6, 0xD9, 0xB9, 0x7D, 0x1C, 0x3C, 0x98, 0xDD, 0x16, 0xE6, 0xD3, 0xAA, 0xEF, 0xB6, 0xB3, 0x53, - 0x74, 0xD1, 0xAC, 0x5C, 0x04, 0x26, 0x7D, 0x71, 0xDE, 0xAB, 0x66, 0x28, 0x91, 0x3A, 0x6F, 0x4F -}; - - -// Alloy (XAO) -const static uint8_t test_output_xao[160] = { - 0x9A, 0x29, 0xD0, 0xC4, 0xAF, 0xDC, 0x63, 0x9B, 0x65, 0x53, 0xB1, 0xC8, 0x37, 0x35, 0x11, 0x4C, - 0x5D, 0x77, 0x16, 0x21, 0x42, 0x97, 0x5C, 0xB8, 0x50, 0xC0, 0xA5, 0x1F, 0x64, 0x07, 0xBD, 0x33, - 0xF1, 0xC9, 0x98, 0x40, 0x42, 0xDE, 0x39, 0xD1, 0xBA, 0x2D, 0xAD, 0xEC, 0xFE, 0xEA, 0xD8, 0x46, - 0x56, 0x1C, 0x32, 0x90, 0x42, 0x63, 0x10, 0x80, 0xD7, 0x01, 0xE4, 0xE6, 0x20, 0xB3, 0x60, 0x45, - 0x05, 0xE5, 0xC2, 0x18, 0xCD, 0x07, 0xA4, 0x40, 0x42, 0x91, 0xE2, 0xA4, 0x52, 0x54, 0x79, 0xBA, - 0xCD, 0x7E, 0x61, 0x2D, 0x7F, 0x7E, 0x69, 0x5E, 0xD7, 0xC0, 0x06, 0x65, 0xD7, 0xA1, 0xB8, 0xB8, - 0x1E, 0x31, 0x1C, 0xD3, 0xB7, 0xBC, 0x78, 0x3C, 0x01, 0xAF, 0x77, 0xAA, 0xF3, 0x0F, 0x4C, 0xF2, - 0xD1, 0x8B, 0x58, 0xC7, 0xEB, 0x99, 0x91, 0x53, 0x43, 0x71, 0x47, 0x99, 0x9E, 0x04, 0xA4, 0xEA, - 0xB8, 0xA3, 0xB0, 0x9E, 0x09, 0xF5, 0x57, 0x5C, 0xCF, 0x8A, 0xC6, 0xCA, 0x88, 0x51, 0x9A, 0x01, - 0x31, 0xCC, 0x0C, 0xA6, 0x53, 0xB5, 0x5F, 0xFD, 0x7D, 0x29, 0x3A, 0x35, 0xE9, 0x0E, 0x25, 0x6C -}; - - -// Arto (RTO) -const static uint8_t test_output_rto[160] = { - 0x82, 0x66, 0x1E, 0x1C, 0x6E, 0x64, 0x36, 0x66, 0x84, 0x06, 0x32, 0x7A, 0x9B, 0xB1, 0x13, 0x19, - 0xA5, 0x56, 0x16, 0x15, 0xDF, 0xEC, 0x1C, 0x9E, 0xE3, 0x88, 0x4A, 0x6C, 0x1C, 0xEB, 0x76, 0xA5, - 0xB3, 0xFB, 0xF4, 0x3F, 0x2B, 0x6A, 0x3A, 0x39, 0xA3, 0x6E, 0x08, 0x33, 0x67, 0x90, 0x31, 0xB9, - 0x3F, 0x27, 0xE4, 0x79, 0x32, 0x61, 0x6B, 0x5C, 0x8A, 0xF8, 0xAF, 0xC0, 0x60, 0xFD, 0x83, 0xB7, - 0x11, 0x11, 0x89, 0xB4, 0xDC, 0xAE, 0x40, 0xC8, 0x64, 0xAA, 0x4D, 0x19, 0x23, 0x7B, 0xD3, 0x27, - 0xB2, 0x0F, 0xA7, 0x50, 0x7D, 0xCA, 0xF5, 0x03, 0x06, 0xB2, 0x26, 0x62, 0xF3, 0x68, 0x2D, 0x30, - 0x6F, 0x93, 0x1E, 0xFF, 0xCD, 0x85, 0x40, 0x28, 0x5F, 0xC3, 0x8C, 0x76, 0x51, 0x9E, 0xD5, 0x06, - 0x32, 0xD6, 0x35, 0x83, 0xF6, 0x3B, 0x54, 0x4F, 0xA1, 0x9C, 0x13, 0xD8, 0xC4, 0x0E, 0x01, 0x2F, - 0x29, 0xDB, 0x8C, 0x1C, 0xB7, 0x06, 0x86, 0x79, 0x6D, 0xFF, 0x9F, 0x89, 0x3B, 0x3A, 0xA5, 0x79, - 0xE7, 0x81, 0x4E, 0x2A, 0xBD, 0x62, 0xC1, 0x1B, 0x7C, 0xB9, 0x33, 0x7B, 0xEE, 0x95, 0x80, 0xB3 -}; - - -#ifndef XMRIG_NO_AEON -const static uint8_t test_output_v0_lite[160] = { - 0x36, 0x95, 0xB4, 0xB5, 0x3B, 0xB0, 0x03, 0x58, 0xB0, 0xAD, 0x38, 0xDC, 0x16, 0x0F, 0xEB, 0x9E, - 0x00, 0x4E, 0xEC, 0xE0, 0x9B, 0x83, 0xA7, 0x2E, 0xF6, 0xBA, 0x98, 0x64, 0xD3, 0x51, 0x0C, 0x88, - 0x28, 0xA2, 0x2B, 0xAD, 0x3F, 0x93, 0xD1, 0x40, 0x8F, 0xCA, 0x47, 0x2E, 0xB5, 0xAD, 0x1C, 0xBE, - 0x75, 0xF2, 0x1D, 0x05, 0x3C, 0x8C, 0xE5, 0xB3, 0xAF, 0x10, 0x5A, 0x57, 0x71, 0x3E, 0x21, 0xDD, - 0x38, 0x08, 0xE1, 0x17, 0x0B, 0x99, 0x8D, 0x1A, 0x3C, 0xCE, 0x35, 0xC5, 0xC7, 0x3A, 0x00, 0x2E, - 0xCB, 0x54, 0xF0, 0x78, 0x2E, 0x9E, 0xDB, 0xC7, 0xDF, 0x2E, 0x71, 0x9A, 0x16, 0x97, 0xC4, 0x18, - 0x4B, 0x97, 0x07, 0xFE, 0x5D, 0x98, 0x9A, 0xD6, 0xD8, 0xE5, 0x92, 0x66, 0x87, 0x7F, 0x19, 0x37, - 0xA2, 0x5E, 0xE6, 0x96, 0xB5, 0x97, 0x33, 0x89, 0xE0, 0xA7, 0xC9, 0xDD, 0x4A, 0x7E, 0x9E, 0x53, - 0xBE, 0x91, 0x2B, 0xF5, 0xF5, 0xAF, 0xDD, 0x09, 0xA2, 0xF4, 0xA4, 0x56, 0xEB, 0x96, 0x22, 0xC9, - 0x94, 0xFB, 0x7B, 0x28, 0xC9, 0x97, 0x65, 0x04, 0xAC, 0x4F, 0x84, 0x71, 0xDA, 0x6E, 0xD8, 0xC5 -}; - - -// AEON v7 -const static uint8_t test_output_v1_lite[160] = { - 0x6D, 0x8C, 0xDC, 0x44, 0x4E, 0x9B, 0xBB, 0xFD, 0x68, 0xFC, 0x43, 0xFC, 0xD4, 0x85, 0x5B, 0x22, - 0x8C, 0x8A, 0x1B, 0xD9, 0x1D, 0x9D, 0x00, 0x28, 0x5B, 0xEC, 0x02, 0xB7, 0xCA, 0x2D, 0x67, 0x41, - 0x87, 0xC4, 0xE5, 0x70, 0x65, 0x3E, 0xB4, 0xC2, 0xB4, 0x2B, 0x7A, 0x0D, 0x54, 0x65, 0x59, 0x45, - 0x2D, 0xFA, 0xB5, 0x73, 0xB8, 0x2E, 0xC5, 0x2F, 0x15, 0x2B, 0x7F, 0xF9, 0x8E, 0x79, 0x44, 0x6F, - 0x16, 0x08, 0x74, 0xC7, 0xA2, 0xD2, 0xA3, 0x97, 0x95, 0x76, 0xCA, 0x4D, 0x06, 0x39, 0x7A, 0xAB, - 0x6C, 0x87, 0x58, 0x33, 0x4D, 0xC8, 0x5A, 0xAB, 0x04, 0x27, 0xFE, 0x8B, 0x1C, 0x23, 0x2F, 0x32, - 0xC0, 0x44, 0xFF, 0x0D, 0xB5, 0x3B, 0x27, 0x96, 0x06, 0x89, 0x7B, 0xA3, 0x0B, 0xD0, 0xCE, 0x9E, - 0x90, 0x22, 0x77, 0x5A, 0xAD, 0xA1, 0xE5, 0xB6, 0xFC, 0xCB, 0x39, 0x7E, 0x2B, 0x10, 0xEE, 0xB4, - 0x8C, 0x2B, 0xA4, 0x1F, 0x60, 0x76, 0x39, 0xD7, 0xF6, 0x46, 0x77, 0x18, 0x20, 0xAD, 0xD4, 0xC9, - 0x87, 0xF7, 0x37, 0xDA, 0xFD, 0xBA, 0xBA, 0xD2, 0xF2, 0x68, 0xDC, 0x26, 0x8D, 0x1B, 0x08, 0xC6 -}; -#endif - - -#ifndef XMRIG_NO_SUMO -const static uint8_t test_output_v0_heavy[160] = { - 0x99, 0x83, 0xF2, 0x1B, 0xDF, 0x20, 0x10, 0xA8, 0xD7, 0x07, 0xBB, 0x2F, 0x14, 0xD7, 0x86, 0x64, - 0xBB, 0xE1, 0x18, 0x7F, 0x55, 0x01, 0x4B, 0x39, 0xE5, 0xF3, 0xD6, 0x93, 0x28, 0xE4, 0x8F, 0xC2, - 0x4D, 0x94, 0x7D, 0xD6, 0xDB, 0x6E, 0x07, 0x48, 0x26, 0x4A, 0x51, 0x2E, 0xAC, 0xF3, 0x25, 0x4A, - 0x1F, 0x1A, 0xA2, 0x5B, 0xFC, 0x0A, 0xAD, 0x82, 0xDE, 0xA8, 0x99, 0x96, 0x88, 0x52, 0xD2, 0x7D, - 0x3E, 0xE1, 0x23, 0x03, 0x5A, 0x63, 0x7B, 0x66, 0xF6, 0xD7, 0xC2, 0x2A, 0x34, 0x5E, 0x88, 0xE7, - 0xFA, 0xC4, 0x25, 0x36, 0x54, 0xCB, 0xD2, 0x5C, 0x2F, 0x80, 0x2A, 0xF9, 0xCC, 0x43, 0xF7, 0xCD, - 0xE5, 0x18, 0xA8, 0x05, 0x60, 0x18, 0xA5, 0x73, 0x72, 0x9B, 0x32, 0xDC, 0x69, 0x83, 0xC1, 0xE1, - 0x1F, 0xDB, 0xDA, 0x6B, 0xAC, 0xEC, 0x9F, 0x67, 0xF8, 0x27, 0x1D, 0xC7, 0xE6, 0x46, 0x42, 0xF9, - 0x53, 0x62, 0x0A, 0x54, 0x7D, 0x43, 0xEA, 0x18, 0x94, 0xED, 0xD8, 0x92, 0x06, 0x6A, 0xA1, 0x51, - 0xAD, 0xB1, 0xFD, 0x89, 0xFB, 0x5C, 0xB4, 0x25, 0x6A, 0xDD, 0xB0, 0x09, 0xC5, 0x72, 0x87, 0xEB -}; - -const static uint8_t test_output_xhv_heavy[160] = { - 0x5A, 0xC3, 0xF7, 0x85, 0xC4, 0x90, 0xC5, 0x85, 0x50, 0xEC, 0x95, 0xD2, 0x72, 0x65, 0x63, 0x57, - 0x7E, 0x7C, 0x1C, 0x21, 0x2D, 0x0C, 0xDE, 0x59, 0x12, 0x73, 0x20, 0x1E, 0x44, 0xFD, 0xD5, 0xB6, - 0x1F, 0x4E, 0xB2, 0x0A, 0x36, 0x51, 0x4B, 0xF5, 0x4D, 0xC9, 0xE0, 0x90, 0x2C, 0x16, 0x47, 0x3F, - 0xDE, 0x18, 0x29, 0x8E, 0xBB, 0x34, 0x2B, 0xEF, 0x7A, 0x04, 0x22, 0xD1, 0xB1, 0xF2, 0x48, 0xDA, - 0xE3, 0x7F, 0x4B, 0x4C, 0xB4, 0xDF, 0xE8, 0xD3, 0x70, 0xE2, 0xE7, 0x44, 0x25, 0x87, 0x12, 0xF9, - 0x8F, 0x28, 0x0B, 0xCE, 0x2C, 0xEE, 0xDD, 0x88, 0x94, 0x35, 0x48, 0x51, 0xAE, 0xC8, 0x9C, 0x0B, - 0xED, 0x2F, 0xE6, 0x0F, 0x39, 0x05, 0xB4, 0x4A, 0x8F, 0x38, 0x44, 0x2D, 0x4B, 0xE9, 0x7B, 0x81, - 0xC6, 0xB0, 0xE0, 0x0A, 0x39, 0x8C, 0x38, 0xFE, 0x63, 0x31, 0x47, 0x65, 0x0D, 0x2B, 0xF4, 0x96, - 0x13, 0x91, 0x89, 0xB4, 0x5B, 0xA9, 0x2A, 0x7A, 0x09, 0x65, 0x14, 0x20, 0x76, 0x24, 0x6C, 0x80, - 0x1D, 0x3F, 0x9F, 0xCD, 0x68, 0x39, 0xA9, 0x42, 0x27, 0xC1, 0x0C, 0x53, 0x98, 0x35, 0x60, 0x7A -}; - - -// TUBE -const static uint8_t test_output_tube_heavy[160] = { - 0xFE, 0x53, 0x35, 0x20, 0x76, 0xEA, 0xE6, 0x89, 0xFA, 0x3B, 0x4F, 0xDA, 0x61, 0x46, 0x34, 0xCF, - 0xC3, 0x12, 0xEE, 0x0C, 0x38, 0x7D, 0xF2, 0xB8, 0xB7, 0x4D, 0xA2, 0xA1, 0x59, 0x74, 0x12, 0x35, - 0xCD, 0x3F, 0x29, 0xDF, 0x07, 0x4A, 0x14, 0xAD, 0x0B, 0x98, 0x99, 0x37, 0xCA, 0x14, 0x68, 0xA3, - 0x8D, 0xAE, 0x86, 0xC1, 0xA3, 0x54, 0x05, 0xBE, 0xEA, 0x6D, 0x29, 0x24, 0x0C, 0x82, 0x97, 0x74, - 0xA0, 0x64, 0x77, 0xCD, 0x8D, 0x8A, 0xC3, 0x10, 0xB4, 0x89, 0x0E, 0xBB, 0x7D, 0xE6, 0x32, 0x8F, - 0xF4, 0x2D, 0xB6, 0x9E, 0x8A, 0xF9, 0xF8, 0xEE, 0x2C, 0xD0, 0x74, 0xED, 0xA9, 0xAA, 0xA1, 0xFB, - 0xE2, 0xC9, 0x89, 0x66, 0xD6, 0x66, 0x52, 0xA2, 0x16, 0xDA, 0x36, 0xA0, 0x10, 0x62, 0xD2, 0xB1, - 0x76, 0xD1, 0x31, 0xE9, 0x1C, 0x08, 0xB6, 0xCA, 0xAF, 0x89, 0xB9, 0x3D, 0x2C, 0xFA, 0x9A, 0x30, - 0x74, 0x6A, 0x96, 0xA1, 0x95, 0x6C, 0xBB, 0x46, 0x4D, 0xE0, 0xEB, 0x28, 0xBE, 0x2A, 0x8C, 0x34, - 0x57, 0x79, 0xBE, 0x52, 0xFB, 0xBC, 0x68, 0x43, 0x45, 0xF4, 0xDF, 0xA5, 0xA8, 0xFD, 0x55, 0xA6 -}; -#endif - - -#endif /* __CRYPTONIGHT_TEST_H__ */ diff --git a/src/Native/libcryptonight/crypto/asm/cnv2_main_loop.asm b/src/Native/libcryptonight/crypto/asm/cnv2_main_loop.asm deleted file mode 100644 index d95222675..000000000 --- a/src/Native/libcryptonight/crypto/asm/cnv2_main_loop.asm +++ /dev/null @@ -1,25 +0,0 @@ -_TEXT_CNV2_MAINLOOP SEGMENT PAGE READ EXECUTE -PUBLIC cnv2_mainloop_ivybridge_asm -PUBLIC cnv2_mainloop_ryzen_asm -PUBLIC cnv2_double_mainloop_sandybridge_asm - -ALIGN 64 -cnv2_mainloop_ivybridge_asm PROC - INCLUDE cnv2_main_loop_ivybridge.inc - ret 0 -cnv2_mainloop_ivybridge_asm ENDP - -ALIGN 64 -cnv2_mainloop_ryzen_asm PROC - INCLUDE cnv2_main_loop_ryzen.inc - ret 0 -cnv2_mainloop_ryzen_asm ENDP - -ALIGN 64 -cnv2_double_mainloop_sandybridge_asm PROC - INCLUDE cnv2_double_main_loop_sandybridge.inc - ret 0 -cnv2_double_mainloop_sandybridge_asm ENDP - -_TEXT_CNV2_MAINLOOP ENDS -END diff --git a/src/Native/libcryptonight/crypto/asm/win64/cnv2_main_loop.S b/src/Native/libcryptonight/crypto/asm/win64/cnv2_main_loop.S deleted file mode 100644 index 78eb11859..000000000 --- a/src/Native/libcryptonight/crypto/asm/win64/cnv2_main_loop.S +++ /dev/null @@ -1,21 +0,0 @@ -#define ALIGN .align -.intel_syntax noprefix -.section .text -.global cnv2_mainloop_ivybridge_asm -.global cnv2_mainloop_ryzen_asm -.global cnv2_double_mainloop_sandybridge_asm - -ALIGN 16 -cnv2_mainloop_ivybridge_asm: - #include "../cnv2_main_loop_ivybridge.inc" - ret 0 - -ALIGN 16 -cnv2_mainloop_ryzen_asm: - #include "../cnv2_main_loop_ryzen.inc" - ret 0 - -ALIGN 16 -cnv2_double_mainloop_sandybridge_asm: - #include "../cnv2_double_main_loop_sandybridge.inc" - ret 0 diff --git a/src/Native/libcryptonight/exports.cpp b/src/Native/libcryptonight/exports.cpp index 65c101b16..d3704b5db 100644 --- a/src/Native/libcryptonight/exports.cpp +++ b/src/Native/libcryptonight/exports.cpp @@ -18,128 +18,201 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include #include -#include "crypto/Asm.h" -#include "crypto/CryptoNight_x86.h" -#include "common/crypto/keccak.h" -#ifdef _WIN32 -#define MODULE_API __declspec(dllexport) +#if defined(__ARM_ARCH) +#include "xmrig/crypto/CryptoNight_arm.h" #else -#define MODULE_API +#include "xmrig/extra.h" +#include "xmrig/crypto/CryptoNight_x86.h" #endif +#include "xmrig/Mem.h" + #if (defined(__AES__) && (__AES__ == 1)) || (defined(__ARM_FEATURE_CRYPTO) && (__ARM_FEATURE_CRYPTO == 1)) #define SOFT_AES false #else -//#warning Using software AES +#warning Using software AES #define SOFT_AES true #endif - -extern "C" MODULE_API int cryptonight_get_context_size_export() { - return sizeof(cryptonight_ctx) + xmrig::CRYPTONIGHT_MEMORY; -} +#ifdef _WIN32 +#define MODULE_API __declspec(dllexport) +#else +#define MODULE_API +#endif extern "C" MODULE_API cryptonight_ctx *cryptonight_alloc_context_export() { - cryptonight_ctx *ctx = static_cast(_mm_malloc(sizeof(cryptonight_ctx), 16)); - ctx->memory = static_cast(_mm_malloc(xmrig::CRYPTONIGHT_MEMORY, 4096)); + cryptonight_ctx *ctx = NULL; + Mem::create(&ctx, xmrig::CRYPTONIGHT, 1); return ctx; } -extern "C" MODULE_API int cryptonight_get_context_lite_size_export() { - return sizeof(cryptonight_ctx) + xmrig::CRYPTONIGHT_LITE_MEMORY; -} - extern "C" MODULE_API cryptonight_ctx *cryptonight_alloc_lite_context_export() { - cryptonight_ctx *ctx = static_cast(_mm_malloc(sizeof(cryptonight_ctx), 16)); - ctx->memory = static_cast(_mm_malloc(xmrig::CRYPTONIGHT_LITE_MEMORY, 4096)); + cryptonight_ctx *ctx = NULL; + Mem::create(&ctx, xmrig::CRYPTONIGHT_LITE, 1); return ctx; } -extern "C" MODULE_API int cryptonight_get_context_heavy_size_export() { - return sizeof(cryptonight_ctx) + xmrig::CRYPTONIGHT_HEAVY_MEMORY; -} - extern "C" MODULE_API cryptonight_ctx *cryptonight_alloc_heavy_context_export() { - cryptonight_ctx *ctx = static_cast(_mm_malloc(sizeof(cryptonight_ctx), 16)); - ctx->memory = static_cast(_mm_malloc(xmrig::CRYPTONIGHT_HEAVY_MEMORY, 4096)); + cryptonight_ctx *ctx = NULL; + Mem::create(&ctx, xmrig::CRYPTONIGHT_HEAVY, 1); return ctx; } +extern "C" MODULE_API cryptonight_ctx *cryptonight_alloc_pico_context_export() { + cryptonight_ctx *ctx = NULL; + Mem::create(&ctx, xmrig::CRYPTONIGHT_PICO, 1); + + return ctx; +} + extern "C" MODULE_API void cryptonight_free_ctx_export(cryptonight_ctx *ctx) { - _mm_free(ctx->memory); - _mm_free(ctx); + MemInfo mi; + Mem::release(&ctx, 1, mi); } -extern "C" MODULE_API void cryptonight_export(cryptonight_ctx* ctx, const char* input, unsigned char *output, uint32_t inputSize, uint32_t variant) +extern "C" MODULE_API void cryptonight_export(cryptonight_ctx* ctx, const char* input, unsigned char *output, size_t inputSize, uint32_t variant, uint64_t height) { switch (variant) { - case 0: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); - break; - case 1: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); - break; - case 2: - case 8: + case 0: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + break; + case 1: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + break; + case 3: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + break; + case 4: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + break; + case 6: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + break; + case 7: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + break; + + case 8: +#if !SOFT_AES && defined(CPU_INTEL) + //#warning Using IvyBridge assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#elif !SOFT_AES && defined(CPU_AMD) + #warning Using Ryzen assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#elif !SOFT_AES && defined(CPU_AMD_OLD) + #warning Using Bulldozer assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#else + cryptonight_single_hash (reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#endif + break; + + case 9: #if !SOFT_AES && defined(CPU_INTEL) - #warning Using IvyBridge assembler implementation - cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); + //#warning Using IvyBridge assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); #elif !SOFT_AES && defined(CPU_AMD) - #warning Using Ryzen assembler implementation - cryptonight_single_hash_asm(reinterpret_cast(Buffer::Data(target)), Buffer::Length(target), reinterpret_cast(output), &ctx); + #warning Using Ryzen assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#elif !SOFT_AES && defined(CPU_AMD_OLD) + #warning Using Bulldozer assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#else + cryptonight_single_hash (reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#endif + break; + case 11: + cryptonight_single_hash_gpu(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + break; + case 12: + //if (!height_set) return THROW_ERROR_EXCEPTION("CryptonightR requires block template height as Argument 3"); + +#if !SOFT_AES && (defined(CPU_INTEL) || defined(CPU_AMD)) + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); #else - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); + cryptonight_single_hash (reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); #endif - break; - case 3: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); - break; - case 4: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); - break; - case 6: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); - break; - case 7: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); - break; - break; - default: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); - } + break; + case 13: + //if (!height_set) return THROW_ERROR_EXCEPTION("Cryptonight4 requires block template height as Argument 3"); + +#if !SOFT_AES && defined(CPU_INTEL) + //#warning Using IvyBridge assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#elif !SOFT_AES && defined(CPU_AMD) + #warning Using Ryzen assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#elif !SOFT_AES && defined(CPU_AMD_OLD) + #warning Using Bulldozer assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#else + cryptonight_single_hash (reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#endif + break; + + default: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + } } -extern "C" MODULE_API void cryptonight_light_export(cryptonight_ctx* ctx, const char* input, unsigned char *output, uint32_t inputSize, uint32_t variant) +extern "C" MODULE_API void cryptonight_light_export(cryptonight_ctx* ctx, const char* input, unsigned char *output, size_t inputSize, uint32_t variant, uint64_t height) { switch (variant) { - case 0: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); - break; - case 1: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); - break; - default: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); - } + case 0: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + break; + case 1: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + break; + default: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + } } -extern "C" MODULE_API void cryptonight_heavy_export(cryptonight_ctx* ctx, const char* input, unsigned char *output, uint32_t inputSize, uint32_t variant) +extern "C" MODULE_API void cryptonight_heavy_export(cryptonight_ctx* ctx, const char* input, unsigned char *output, size_t inputSize, uint32_t variant, uint64_t height) { switch (variant) { - case 0: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); - break; - case 1: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); - break; - case 2: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); - break; - default: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx); - } + case 0: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + break; + case 1: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + break; + case 2: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + break; + default: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + } +} + +extern "C" MODULE_API void cryptonight_pico_export(cryptonight_ctx* ctx, const char* input, unsigned char *output, size_t inputSize, uint32_t variant, uint64_t height) +{ + switch (variant) { + case 0: +#if !SOFT_AES && defined(CPU_INTEL) + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, 0); +#elif !SOFT_AES && defined(CPU_AMD) + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, 0); +#elif !SOFT_AES && defined(CPU_AMD_OLD) + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, 0); +#else + cryptonight_single_hash (reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, 0); +#endif + break; + default: +#if !SOFT_AES && defined(CPU_INTEL) + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, 0); +#elif !SOFT_AES && defined(CPU_AMD) + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, 0); +#elif !SOFT_AES && defined(CPU_AMD_OLD) + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, 0); +#else + cryptonight_single_hash (reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, 0); +#endif + } } diff --git a/src/Native/libcryptonight/libcryptonight.vcxproj b/src/Native/libcryptonight/libcryptonight.vcxproj index 0cf481444..2fa7b019a 100644 --- a/src/Native/libcryptonight/libcryptonight.vcxproj +++ b/src/Native/libcryptonight/libcryptonight.vcxproj @@ -75,22 +75,22 @@ true $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;$(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0 - $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)3rdparty;$(IncludePath);$(ProjectDir)3rdparty + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)xmrig;$(IncludePath);$(ProjectDir)xmrig\3rdparty true $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;$(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0 - $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)3rdparty;$(IncludePath);$(ProjectDir)3rdparty + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)xmrig;$(IncludePath);$(ProjectDir)xmrig\3rdparty false $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;$(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0 - $(VC_IncludePath);$(WindowsSDK_IncludePath);$(IncludePath);$(ProjectDir)3rdparty + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(IncludePath);$(ProjectDir)xmrig;$(IncludePath);$(ProjectDir)xmrig\3rdparty false $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;$(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0 - $(VC_IncludePath);$(WindowsSDK_IncludePath);$(IncludePath);$(ProjectDir)3rdparty + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(IncludePath);$(ProjectDir)xmrig;$(IncludePath);$(ProjectDir)xmrig\3rdparty @@ -169,47 +169,59 @@ - - - - - - - - - - - - - - - - - - - - + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + Document + + Document - - + + diff --git a/src/Native/libcryptonight/3rdparty/aligned_malloc.h b/src/Native/libcryptonight/xmrig/3rdparty/aligned_malloc.h similarity index 100% rename from src/Native/libcryptonight/3rdparty/aligned_malloc.h rename to src/Native/libcryptonight/xmrig/3rdparty/aligned_malloc.h diff --git a/src/Native/libcryptonight/xmrig/Mem.cpp b/src/Native/libcryptonight/xmrig/Mem.cpp new file mode 100644 index 000000000..4fa794d65 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/Mem.cpp @@ -0,0 +1,77 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "common/utils/mm_malloc.h" +#include "crypto/CryptoNight.h" +#include "crypto/CryptoNight_constants.h" +#include "Mem.h" + + +bool Mem::m_enabled = true; +int Mem::m_flags = 0; + + +MemInfo Mem::create(cryptonight_ctx **ctx, xmrig::Algo algorithm, size_t count) +{ + using namespace xmrig; + + MemInfo info; + info.size = cn_select_memory(algorithm) * count; + + constexpr const size_t align_size = 2 * 1024 * 1024; + info.size = ((info.size + align_size - 1) / align_size) * align_size; + info.pages = info.size / align_size; + + allocate(info, m_enabled); + + for (size_t i = 0; i < count; ++i) { + cryptonight_ctx *c = static_cast(_mm_malloc(sizeof(cryptonight_ctx), 4096)); + c->memory = info.memory + (i * cn_select_memory(algorithm)); + + uint8_t* p = reinterpret_cast(allocateExecutableMemory(0x4000)); + c->generated_code = reinterpret_cast(p); + c->generated_code_double = reinterpret_cast(p + 0x2000); + + c->generated_code_data.variant = xmrig::VARIANT_MAX; + c->generated_code_data.height = (uint64_t)(-1); + c->generated_code_double_data = c->generated_code_data; + + ctx[i] = c; + } + + return info; +} + + +void Mem::release(cryptonight_ctx **ctx, size_t count, MemInfo &info) +{ + release(info); + + for (size_t i = 0; i < count; ++i) { + _mm_free(ctx[i]); + } +} + diff --git a/src/Native/libcryptonight/xmrig/Mem.h b/src/Native/libcryptonight/xmrig/Mem.h new file mode 100644 index 000000000..9e39e963c --- /dev/null +++ b/src/Native/libcryptonight/xmrig/Mem.h @@ -0,0 +1,78 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_MEM_H +#define XMRIG_MEM_H + + +#include +#include + + +#include "common/xmrig.h" + + +struct cryptonight_ctx; + + +struct MemInfo +{ + alignas(16) uint8_t *memory; + + size_t hugePages; + size_t pages; + size_t size; +}; + + +class Mem +{ +public: + enum Flags { + HugepagesAvailable = 1, + HugepagesEnabled = 2, + Lock = 4 + }; + + static MemInfo create(cryptonight_ctx **ctx, xmrig::Algo algorithm, size_t count); + static void init(bool enabled); + static void release(cryptonight_ctx **ctx, size_t count, MemInfo &info); + + static void *allocateExecutableMemory(size_t size); + static void protectExecutableMemory(void *p, size_t size); + static void flushInstructionCache(void *p, size_t size); + + static inline bool isHugepagesAvailable() { return (m_flags & HugepagesAvailable) != 0; } + +private: + static void allocate(MemInfo &info, bool enabled); + static void release(MemInfo &info); + + static int m_flags; + static bool m_enabled; +}; + + +#endif /* XMRIG_MEM_H */ diff --git a/src/Native/libcryptonight/xmrig/Mem_unix.cpp b/src/Native/libcryptonight/xmrig/Mem_unix.cpp new file mode 100644 index 000000000..a1bec3d4f --- /dev/null +++ b/src/Native/libcryptonight/xmrig/Mem_unix.cpp @@ -0,0 +1,113 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include + + +#include "common/utils/mm_malloc.h" +#include "common/xmrig.h" +#include "crypto/CryptoNight.h" +#include "Mem.h" + + +void Mem::init(bool enabled) +{ + m_enabled = enabled; +} + + +void Mem::allocate(MemInfo &info, bool enabled) +{ + info.hugePages = 0; + + if (!enabled) { + info.memory = static_cast(_mm_malloc(info.size, 4096)); + + return; + } + +# if defined(__APPLE__) + info.memory = static_cast(mmap(0, info.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0)); +# elif defined(__FreeBSD__) + info.memory = static_cast(mmap(0, info.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER | MAP_PREFAULT_READ, -1, 0)); +# else + info.memory = static_cast(mmap(0, info.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, 0, 0)); +# endif + + if (info.memory == MAP_FAILED) { + return allocate(info, false);; + } + + info.hugePages = info.pages; + + if (madvise(info.memory, info.size, MADV_RANDOM | MADV_WILLNEED) != 0) { + //LOG_ERR("madvise failed"); + } + + if (mlock(info.memory, info.size) == 0) { + m_flags |= Lock; + } +} + + +void Mem::release(MemInfo &info) +{ + if (info.hugePages) { + if (m_flags & Lock) { + munlock(info.memory, info.size); + } + + munmap(info.memory, info.size); + } + else { + _mm_free(info.memory); + } +} + + +void *Mem::allocateExecutableMemory(size_t size) +{ +# if defined(__APPLE__) + return mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); +# else + return mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +# endif +} + + +void Mem::protectExecutableMemory(void *p, size_t size) +{ + mprotect(p, size, PROT_READ | PROT_EXEC); +} + + +void Mem::flushInstructionCache(void *p, size_t size) +{ +# ifndef __FreeBSD__ + __builtin___clear_cache(reinterpret_cast(p), reinterpret_cast(p) + size); +# endif +} diff --git a/src/Native/libcryptonight/xmrig/Mem_win.cpp b/src/Native/libcryptonight/xmrig/Mem_win.cpp new file mode 100644 index 000000000..e6b4353a1 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/Mem_win.cpp @@ -0,0 +1,203 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include + + +#include "common/utils/mm_malloc.h" +#include "common/xmrig.h" +#include "crypto/CryptoNight.h" +#include "crypto/CryptoNight_constants.h" +#include "Mem.h" + + +/***************************************************************** +SetLockPagesPrivilege: a function to obtain or +release the privilege of locking physical pages. + +Inputs: + +HANDLE hProcess: Handle for the process for which the +privilege is needed + +BOOL bEnable: Enable (TRUE) or disable? + +Return value: TRUE indicates success, FALSE failure. + +*****************************************************************/ +/** + * AWE Example: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366531(v=vs.85).aspx + * Creating a File Mapping Using Large Pages: https://msdn.microsoft.com/en-us/library/aa366543(VS.85).aspx + */ +static BOOL SetLockPagesPrivilege() { + HANDLE token; + + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) != TRUE) { + return FALSE; + } + + TOKEN_PRIVILEGES tp; + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &(tp.Privileges[0].Luid)) != TRUE) { + return FALSE; + } + + BOOL rc = AdjustTokenPrivileges(token, FALSE, (PTOKEN_PRIVILEGES) &tp, 0, NULL, NULL); + if (rc != TRUE || GetLastError() != ERROR_SUCCESS) { + return FALSE; + } + + CloseHandle(token); + + return TRUE; +} + + +static LSA_UNICODE_STRING StringToLsaUnicodeString(LPCTSTR string) { + LSA_UNICODE_STRING lsaString; + + DWORD dwLen = (DWORD) wcslen(string); + lsaString.Buffer = (LPWSTR) string; + lsaString.Length = (USHORT)((dwLen) * sizeof(WCHAR)); + lsaString.MaximumLength = (USHORT)((dwLen + 1) * sizeof(WCHAR)); + return lsaString; +} + + +static BOOL ObtainLockPagesPrivilege() { + HANDLE token; + PTOKEN_USER user = NULL; + + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token) == TRUE) { + DWORD size = 0; + + GetTokenInformation(token, TokenUser, NULL, 0, &size); + if (size) { + user = (PTOKEN_USER) LocalAlloc(LPTR, size); + } + + GetTokenInformation(token, TokenUser, user, size, &size); + CloseHandle(token); + } + + if (!user) { + return FALSE; + } + + LSA_HANDLE handle; + LSA_OBJECT_ATTRIBUTES attributes; + ZeroMemory(&attributes, sizeof(attributes)); + + BOOL result = FALSE; + if (LsaOpenPolicy(NULL, &attributes, POLICY_ALL_ACCESS, &handle) == 0) { + LSA_UNICODE_STRING str = StringToLsaUnicodeString(SE_LOCK_MEMORY_NAME); + + if (LsaAddAccountRights(handle, user->User.Sid, &str, 1) == 0) { + //LOG_NOTICE("Huge pages support was successfully enabled, but reboot required to use it"); + result = TRUE; + } + + LsaClose(handle); + } + + LocalFree(user); + return result; +} + + +static BOOL TrySetLockPagesPrivilege() { + if (SetLockPagesPrivilege()) { + return TRUE; + } + + return ObtainLockPagesPrivilege() && SetLockPagesPrivilege(); +} + + +void Mem::init(bool enabled) +{ + m_enabled = enabled; + + if (enabled && TrySetLockPagesPrivilege()) { + m_flags |= HugepagesAvailable; + } +} + + +void Mem::allocate(MemInfo &info, bool enabled) +{ + info.hugePages = 0; + + if (!enabled) { + info.memory = static_cast(_mm_malloc(info.size, 4096)); + + return; + } + + info.memory = static_cast(VirtualAlloc(nullptr, info.size, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE)); + if (info.memory) { + info.hugePages = info.pages; + + return; + } + + allocate(info, false); +} + + +void Mem::release(MemInfo &info) +{ + if (info.hugePages) { + VirtualFree(info.memory, 0, MEM_RELEASE); + } + else { + _mm_free(info.memory); + } +} + + +void *Mem::allocateExecutableMemory(size_t size) +{ + return VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); +} + + +void Mem::protectExecutableMemory(void *p, size_t size) +{ + DWORD oldProtect; + VirtualProtect(p, size, PAGE_EXECUTE_READ, &oldProtect); +} + + +void Mem::flushInstructionCache(void *p, size_t size) +{ + ::FlushInstructionCache(GetCurrentProcess(), p, size); +} diff --git a/src/Native/libcryptonight/xmrig/common/cpu/BasicCpuInfo.cpp b/src/Native/libcryptonight/xmrig/common/cpu/BasicCpuInfo.cpp new file mode 100644 index 000000000..e9018c98a --- /dev/null +++ b/src/Native/libcryptonight/xmrig/common/cpu/BasicCpuInfo.cpp @@ -0,0 +1,146 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + + +#ifdef _MSC_VER +# include +#else +# include +#endif + +#ifndef bit_AES +# define bit_AES (1 << 25) +#endif + +#ifndef bit_AVX2 +# define bit_AVX2 (1 << 5) +#endif + + +#include "common/cpu/BasicCpuInfo.h" + + +#define VENDOR_ID (0) +#define PROCESSOR_INFO (1) +#define CACHE_TLB_DESCRIPTOR (2) +#define EXTENDED_FEATURES (7) +#define PROCESSOR_BRAND_STRING_1 (0x80000002) +#define PROCESSOR_BRAND_STRING_2 (0x80000003) +#define PROCESSOR_BRAND_STRING_3 (0x80000004) + +#define EAX_Reg (0) +#define EBX_Reg (1) +#define ECX_Reg (2) +#define EDX_Reg (3) + + +#ifdef _MSC_VER +static inline void cpuid(int level, int output[4]) { + __cpuid(output, level); +} +#else +static inline void cpuid(int level, int output[4]) { + int a, b, c, d; + __cpuid_count(level, 0, a, b, c, d); + + output[0] = a; + output[1] = b; + output[2] = c; + output[3] = d; +} +#endif + + +static inline void cpu_brand_string(char* s) { + int32_t cpu_info[4] = { 0 }; + cpuid(VENDOR_ID, cpu_info); + + if (cpu_info[EAX_Reg] >= 4) { + for (int i = 0; i < 4; i++) { + cpuid(0x80000002 + i, cpu_info); + memcpy(s, cpu_info, sizeof(cpu_info)); + s += 16; + } + } +} + + +static inline bool has_aes_ni() +{ + int32_t cpu_info[4] = { 0 }; + cpuid(PROCESSOR_INFO, cpu_info); + + return (cpu_info[ECX_Reg] & bit_AES) != 0; +} + + +static inline bool has_avx2() +{ + int32_t cpu_info[4] = { 0 }; + cpuid(EXTENDED_FEATURES, cpu_info); + + return (cpu_info[EBX_Reg] & bit_AVX2) != 0; +} + + +xmrig::BasicCpuInfo::BasicCpuInfo() : + m_assembly(ASM_NONE), + m_aes(has_aes_ni()), + m_avx2(has_avx2()), + m_brand(), + m_threads(std::thread::hardware_concurrency()) +{ + cpu_brand_string(m_brand); + +# ifndef XMRIG_NO_ASM + if (hasAES()) { + char vendor[13] = { 0 }; + int32_t data[4] = { 0 }; + + cpuid(0, data); + + memcpy(vendor + 0, &data[1], 4); + memcpy(vendor + 4, &data[3], 4); + memcpy(vendor + 8, &data[2], 4); + + if (memcmp(vendor, "GenuineIntel", 12) == 0) { + m_assembly = ASM_INTEL; + } + else if (memcmp(vendor, "AuthenticAMD", 12) == 0) { + m_assembly = ASM_RYZEN; + } + } +# endif +} + + +size_t xmrig::BasicCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsage) const +{ + const size_t count = threads() / 2; + + return count < 1 ? 1 : count; +} diff --git a/src/Native/libcryptonight/xmrig/common/cpu/BasicCpuInfo.h b/src/Native/libcryptonight/xmrig/common/cpu/BasicCpuInfo.h new file mode 100644 index 000000000..95857ed27 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/common/cpu/BasicCpuInfo.h @@ -0,0 +1,73 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_BASICCPUINFO_H +#define XMRIG_BASICCPUINFO_H + + +#include "common/interfaces/ICpuInfo.h" + + +namespace xmrig { + + +class BasicCpuInfo : public ICpuInfo +{ +public: + BasicCpuInfo(); + +protected: + size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const override; + + inline Assembly assembly() const override { return m_assembly; } + inline bool hasAES() const override { return m_aes; } + inline bool hasAVX2() const override { return m_avx2; } + inline bool isSupported() const override { return true; } + inline const char *brand() const override { return m_brand; } + inline int32_t cores() const override { return -1; } + inline int32_t L2() const override { return -1; } + inline int32_t L3() const override { return -1; } + inline int32_t nodes() const override { return -1; } + inline int32_t sockets() const override { return 1; } + inline int32_t threads() const override { return m_threads; } + +# if defined(__x86_64__) || defined(_M_AMD64) || defined (__arm64__) || defined (__aarch64__) + inline bool isX64() const override { return true; } +# else + inline bool isX64() const override { return false; } +# endif + +private: + Assembly m_assembly; + bool m_aes; + bool m_avx2; + char m_brand[64]; + int32_t m_threads; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_BASICCPUINFO_H */ diff --git a/src/Native/libcryptonight/xmrig/common/cpu/BasicCpuInfo_arm.cpp b/src/Native/libcryptonight/xmrig/common/cpu/BasicCpuInfo_arm.cpp new file mode 100644 index 000000000..339613466 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/common/cpu/BasicCpuInfo_arm.cpp @@ -0,0 +1,58 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#if __ARM_FEATURE_CRYPTO +# include +# include +#endif + + +#include "common/cpu/BasicCpuInfo.h" + + +xmrig::BasicCpuInfo::BasicCpuInfo() : + m_aes(false), + m_avx2(false), + m_brand(), + m_threads(std::thread::hardware_concurrency()) +{ +# ifdef XMRIG_ARMv8 + memcpy(m_brand, "ARMv8", 5); +# else + memcpy(m_brand, "ARMv7", 5); +# endif + +# if __ARM_FEATURE_CRYPTO + m_aes = getauxval(AT_HWCAP) & HWCAP_AES; +# endif +} + + +size_t xmrig::BasicCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsage) const +{ + return threads(); +} diff --git a/src/Native/libcryptonight/xmrig/common/cpu/Cpu.cpp b/src/Native/libcryptonight/xmrig/common/cpu/Cpu.cpp new file mode 100644 index 000000000..b1bb28ac7 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/common/cpu/Cpu.cpp @@ -0,0 +1,57 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "common/cpu/BasicCpuInfo.h" +#include "common/cpu/Cpu.h" + + +static xmrig::ICpuInfo *cpuInfo = nullptr; + + +xmrig::ICpuInfo *xmrig::Cpu::info() +{ + assert(cpuInfo != nullptr); + + return cpuInfo; +} + + +void xmrig::Cpu::init() +{ + assert(cpuInfo == nullptr); + + cpuInfo = new BasicCpuInfo(); +} + + +void xmrig::Cpu::release() +{ + assert(cpuInfo != nullptr); + + delete cpuInfo; + cpuInfo = nullptr; +} diff --git a/src/Native/libcryptonight/crypto/CryptoNight.h b/src/Native/libcryptonight/xmrig/common/cpu/Cpu.h similarity index 80% rename from src/Native/libcryptonight/crypto/CryptoNight.h rename to src/Native/libcryptonight/xmrig/common/cpu/Cpu.h index 680f1740e..1d5a9fb1d 100644 --- a/src/Native/libcryptonight/crypto/CryptoNight.h +++ b/src/Native/libcryptonight/xmrig/common/cpu/Cpu.h @@ -5,7 +5,6 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , - * Copyright 2018 Lee Clagett * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -22,18 +21,26 @@ * along with this program. If not, see . */ -#ifndef XMRIG_CRYPTONIGHT_H -#define XMRIG_CRYPTONIGHT_H +#ifndef XMRIG_CPU_H +#define XMRIG_CPU_H -#include -#include +#include "common/interfaces/ICpuInfo.h" -struct cryptonight_ctx { - alignas(16) uint8_t state[224]; - alignas(16) uint8_t *memory; +namespace xmrig { + + +class Cpu +{ +public: + static ICpuInfo *info(); + static void init(); + static void release(); }; -#endif /* XMRIG_CRYPTONIGHT_H */ +} /* namespace xmrig */ + + +#endif /* XMRIG_CPU_H */ diff --git a/src/Native/libcryptonight/common/crypto/keccak.cpp b/src/Native/libcryptonight/xmrig/common/crypto/keccak.cpp similarity index 98% rename from src/Native/libcryptonight/common/crypto/keccak.cpp rename to src/Native/libcryptonight/xmrig/common/crypto/keccak.cpp index 0e65b1dfc..0219ce366 100644 --- a/src/Native/libcryptonight/common/crypto/keccak.cpp +++ b/src/Native/libcryptonight/xmrig/common/crypto/keccak.cpp @@ -37,14 +37,14 @@ #define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) #endif -const uint64_t keccakf_rndc[24] = +const uint64_t keccakf_rndc[24] = { 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, - 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 }; @@ -155,7 +155,7 @@ void xmrig::keccakf(uint64_t st[25], int rounds) st[j + 2] ^= (~bc[3]) & bc[4]; st[j + 3] ^= (~bc[4]) & bc[0]; st[j + 4] ^= (~bc[0]) & bc[1]; - + // Iota st[0] ^= keccakf_rndc[round]; } @@ -173,7 +173,7 @@ void xmrig::keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen) rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; rsizw = rsiz / 8; - + memset(st, 0, sizeof(st)); for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) { diff --git a/src/Native/libcryptonight/common/crypto/keccak.h b/src/Native/libcryptonight/xmrig/common/crypto/keccak.h similarity index 100% rename from src/Native/libcryptonight/common/crypto/keccak.h rename to src/Native/libcryptonight/xmrig/common/crypto/keccak.h diff --git a/src/Native/libcryptonight/xmrig/common/interfaces/ICpuInfo.h b/src/Native/libcryptonight/xmrig/common/interfaces/ICpuInfo.h new file mode 100644 index 000000000..dd4034b33 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/common/interfaces/ICpuInfo.h @@ -0,0 +1,63 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CPUINFO_H +#define XMRIG_CPUINFO_H + + +#include +#include + + +#include "common/xmrig.h" + + +namespace xmrig { + + +class ICpuInfo +{ +public: + virtual ~ICpuInfo() {} + + virtual bool hasAES() const = 0; + virtual bool hasAVX2() const = 0; + virtual bool isSupported() const = 0; + virtual bool isX64() const = 0; + virtual const char *brand() const = 0; + virtual int32_t cores() const = 0; + virtual int32_t L2() const = 0; + virtual int32_t L3() const = 0; + virtual int32_t nodes() const = 0; + virtual int32_t sockets() const = 0; + virtual int32_t threads() const = 0; + virtual size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const = 0; + virtual xmrig::Assembly assembly() const = 0; +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_CPUINFO_H diff --git a/src/Native/libcryptonight/common/utils/mm_malloc.h b/src/Native/libcryptonight/xmrig/common/utils/mm_malloc.h similarity index 100% rename from src/Native/libcryptonight/common/utils/mm_malloc.h rename to src/Native/libcryptonight/xmrig/common/utils/mm_malloc.h diff --git a/src/Native/libcryptonight/xmrig/common/xmrig.h b/src/Native/libcryptonight/xmrig/common/xmrig.h new file mode 100644 index 000000000..c6a5f5688 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/common/xmrig.h @@ -0,0 +1,118 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_XMRIG_H +#define XMRIG_XMRIG_H + + +namespace xmrig +{ + + +enum Algo { + INVALID_ALGO = -1, + CRYPTONIGHT, /* CryptoNight (2 MB) */ + CRYPTONIGHT_LITE, /* CryptoNight (1 MB) */ + CRYPTONIGHT_HEAVY, /* CryptoNight (4 MB) */ + CRYPTONIGHT_PICO, /* CryptoNight (256 KB) */ + ALGO_MAX +}; + + +//--av=1 For CPUs with hardware AES. +//--av=2 Lower power mode (double hash) of 1. +//--av=3 Software AES implementation. +//--av=4 Lower power mode (double hash) of 3. +enum AlgoVariant { + AV_AUTO, // --av=0 Automatic mode. + AV_SINGLE, // --av=1 Single hash mode + AV_DOUBLE, // --av=2 Double hash mode + AV_SINGLE_SOFT, // --av=3 Single hash mode (Software AES) + AV_DOUBLE_SOFT, // --av=4 Double hash mode (Software AES) + AV_TRIPLE, // --av=5 Triple hash mode + AV_QUAD, // --av=6 Quard hash mode + AV_PENTA, // --av=7 Penta hash mode + AV_TRIPLE_SOFT, // --av=8 Triple hash mode (Software AES) + AV_QUAD_SOFT, // --av=9 Quard hash mode (Software AES) + AV_PENTA_SOFT, // --av=10 Penta hash mode (Software AES) + AV_MAX +}; + + +enum Variant { + VARIANT_AUTO = -1, // Autodetect + VARIANT_0 = 0, // Original CryptoNight or CryptoNight-Heavy + VARIANT_1 = 1, // CryptoNight variant 1 also known as Monero7 and CryptoNightV7 + VARIANT_TUBE = 2, // Modified CryptoNight-Heavy (TUBE only) + VARIANT_XTL = 3, // Modified CryptoNight variant 1 (Stellite only) + VARIANT_MSR = 4, // Modified CryptoNight variant 1 (Masari only) + VARIANT_XHV = 5, // Modified CryptoNight-Heavy (Haven Protocol only) + VARIANT_XAO = 6, // Modified CryptoNight variant 0 (Alloy only) + VARIANT_RTO = 7, // Modified CryptoNight variant 1 (Arto only) + VARIANT_2 = 8, // CryptoNight variant 2 + VARIANT_HALF = 9, // CryptoNight variant 2 with half iterations (Masari/Stellite) + VARIANT_TRTL = 10, // CryptoNight Turtle (TRTL) + VARIANT_GPU = 11, // CryptoNight-GPU (Ryo) + VARIANT_WOW = 12, // CryptoNightR (Wownero) + VARIANT_4 = 13, // CryptoNightR (Monero's variant 4) + VARIANT_MAX +}; + + +enum AlgoVerify { + VERIFY_HW_AES = 1, + VERIFY_SOFT_AES = 2 +}; + + +enum AesMode { + AES_AUTO, + AES_HW, + AES_SOFT +}; + + +enum OclVendor { + OCL_VENDOR_UNKNOWN = -2, + OCL_VENDOR_MANUAL = -1, + OCL_VENDOR_AMD = 0, + OCL_VENDOR_NVIDIA = 1, + OCL_VENDOR_INTEL = 2 +}; + + +enum Assembly { + ASM_NONE, + ASM_AUTO, + ASM_INTEL, + ASM_RYZEN, + ASM_BULLDOZER, + ASM_MAX +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_XMRIG_H */ diff --git a/src/Native/libcryptonight/xmrig/crypto/CryptoNight.h b/src/Native/libcryptonight/xmrig/crypto/CryptoNight.h new file mode 100644 index 000000000..b92945e4e --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/CryptoNight.h @@ -0,0 +1,59 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CRYPTONIGHT_H +#define XMRIG_CRYPTONIGHT_H + + +#include +#include + +#if defined _MSC_VER || defined XMRIG_ARM +#define ABI_ATTRIBUTE +#else +#define ABI_ATTRIBUTE __attribute__((ms_abi)) +#endif + +struct cryptonight_ctx; +typedef void(*cn_mainloop_fun_ms_abi)(cryptonight_ctx*) ABI_ATTRIBUTE; +typedef void(*cn_mainloop_double_fun_ms_abi)(cryptonight_ctx*, cryptonight_ctx*) ABI_ATTRIBUTE; + +struct cryptonight_r_data { + int variant; + uint64_t height; + + bool match(const int v, const uint64_t h) const { return (v == variant) && (h == height); } +}; + +struct cryptonight_ctx { + alignas(16) uint8_t state[224]; + alignas(16) uint8_t *memory; + cn_mainloop_fun_ms_abi generated_code; + cn_mainloop_double_fun_ms_abi generated_code_double; + cryptonight_r_data generated_code_data; + cryptonight_r_data generated_code_double_data; +}; + + +#endif /* XMRIG_CRYPTONIGHT_H */ diff --git a/src/Native/libcryptonight/crypto/CryptoNight_arm.h b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_arm.h similarity index 79% rename from src/Native/libcryptonight/crypto/CryptoNight_arm.h rename to src/Native/libcryptonight/xmrig/crypto/CryptoNight_arm.h index 4fcebc3ee..e7232eb1f 100644 --- a/src/Native/libcryptonight/crypto/CryptoNight_arm.h +++ b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_arm.h @@ -5,10 +5,10 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2016 Imran Yusuff - * Copyright 2017-2018 XMR-Stak , + * Copyright 2017-2019 XMR-Stak , * Copyright 2018 Lee Clagett - * Copyright 2018 SChernykh - * Copyright 2016-2018 XMRig , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -284,6 +284,34 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) } +#ifndef XMRIG_NO_CN_GPU +template +void cn_explode_scratchpad_gpu(const uint8_t *input, uint8_t *output) +{ + constexpr size_t hash_size = 200; // 25x8 bytes + alignas(16) uint64_t hash[25]; + + for (uint64_t i = 0; i < MEM / 512; i++) + { + memcpy(hash, input, hash_size); + hash[0] ^= i; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 160); + output += 160; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 176); + output += 176; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 176); + output += 176; + } +} +#endif + + template static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) { @@ -402,13 +430,13 @@ static inline __m128i aes_round_tweak_div(const __m128i &in, const __m128i &key) } -template -static inline void cryptonight_monero_tweak(const uint8_t* l, uint64_t idx, __m128i ax0, __m128i bx0, __m128i bx1, __m128i cx) +template +static inline void cryptonight_monero_tweak(const uint8_t* l, uint64_t idx, __m128i ax0, __m128i bx0, __m128i bx1, __m128i& cx) { uint64_t* mem_out = (uint64_t*)&l[idx]; - if (VARIANT == xmrig::VARIANT_2) { - VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1); + if (BASE == xmrig::VARIANT_2) { + VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1, cx); _mm_store_si128((__m128i *)mem_out, _mm_xor_si128(bx0, cx)); } else { __m128i tmp = _mm_xor_si128(bx0, cx); @@ -427,14 +455,14 @@ static inline void cryptonight_monero_tweak(const uint8_t* l, uint64_t idx, __m1 template -inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr bool IS_V1 = xmrig::cn_base_variant() == xmrig::VARIANT_1; + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); - if (IS_V1 && size < 43) { + if (BASE == xmrig::VARIANT_1 && size < 43) { memset(output, 0, 32); return; } @@ -448,6 +476,7 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si VARIANT1_INIT(0); VARIANT2_INIT(0); + VARIANT4_RANDOM_MATH_INIT(0); uint64_t al0 = h0[0] ^ h0[4]; uint64_t ah0 = h0[1] ^ h0[5]; @@ -473,8 +502,8 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si cx = _mm_aesenc_si128(cx, ax0); } - if (IS_V1 || VARIANT == xmrig::VARIANT_2) { - cryptonight_monero_tweak(l0, idx0 & MASK, ax0, bx0, bx1, cx); + if (BASE == xmrig::VARIANT_1 || BASE == xmrig::VARIANT_2) { + cryptonight_monero_tweak(l0, idx0 & MASK, ax0, bx0, bx1, cx); } else { _mm_store_si128((__m128i *)&l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); } @@ -484,13 +513,27 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si uint64_t hi, lo, cl, ch; cl = ((uint64_t*) &l0[idx0 & MASK])[0]; ch = ((uint64_t*) &l0[idx0 & MASK])[1]; - if (VARIANT == xmrig::VARIANT_2) { - VARIANT2_INTEGER_MATH(0, cl, cx); - lo = __umul128(idx0, cl, &hi); - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo); + + if (BASE == xmrig::VARIANT_2) { + if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + VARIANT4_RANDOM_MATH(0, al0, ah0, cl, bx0, bx1); + if (VARIANT == xmrig::VARIANT_4) { + al0 ^= r0[2] | ((uint64_t)(r0[3]) << 32); + ah0 ^= r0[0] | ((uint64_t)(r0[1]) << 32); + } + } else { + VARIANT2_INTEGER_MATH(0, cl, cx); + } } - else { - lo = __umul128(idx0, cl, &hi); + + lo = __umul128(idx0, cl, &hi); + + if (BASE == xmrig::VARIANT_2) { + if (VARIANT == xmrig::VARIANT_4) { + VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx0, bx1, cx); + } else { + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo); + } } al0 += hi; @@ -498,9 +541,9 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l0[idx0 & MASK])[0] = al0; - if (IS_V1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; - } else if (IS_V1) { + } else if (BASE == xmrig::VARIANT_1) { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; } else { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0; @@ -525,9 +568,11 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si idx0 = d ^ q; } } - if (VARIANT == xmrig::VARIANT_2) { + + if (BASE == xmrig::VARIANT_2) { bx1 = bx0; } + bx0 = cx; } @@ -538,15 +583,44 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si } +#ifndef XMRIG_NO_CN_GPU +template +void cn_gpu_inner_arm(const uint8_t *spad, uint8_t *lpad); + + template -inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx) +inline void cryptonight_single_hash_gpu(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr bool IS_V1 = xmrig::cn_base_variant() == xmrig::VARIANT_1; + constexpr size_t MASK = xmrig::CRYPTONIGHT_GPU_MASK; + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + + static_assert(MASK > 0 && ITERATIONS > 0 && MEM > 0, "unsupported algorithm/variant"); + + xmrig::keccak(input, size, ctx[0]->state); + cn_explode_scratchpad_gpu(ctx[0]->state, ctx[0]->memory); + + fesetround(FE_TONEAREST); - if (IS_V1 && size < 43) { + cn_gpu_inner_arm(ctx[0]->state, ctx[0]->memory); + + cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); + + xmrig::keccakf((uint64_t*) ctx[0]->state, 24); + memcpy(output, ctx[0]->state, 32); +} +#endif + + +template +inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx, uint64_t height) +{ + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + + if (BASE == xmrig::VARIANT_1 && size < 43) { memset(output, 0, 64); return; } @@ -563,6 +637,8 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si VARIANT1_INIT(1); VARIANT2_INIT(0); VARIANT2_INIT(1); + VARIANT4_RANDOM_MATH_INIT(0); + VARIANT4_RANDOM_MATH_INIT(1); cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0); cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1); @@ -602,9 +678,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si cx1 = _mm_aesenc_si128(cx1, ax1); } - if (IS_V1 || (VARIANT == xmrig::VARIANT_2)) { - cryptonight_monero_tweak(l0, idx0 & MASK, ax0, bx00, bx01, cx0); - cryptonight_monero_tweak(l1, idx1 & MASK, ax1, bx10, bx11, cx1); + if (BASE == xmrig::VARIANT_1 || (BASE == xmrig::VARIANT_2)) { + cryptonight_monero_tweak(l0, idx0 & MASK, ax0, bx00, bx01, cx0); + cryptonight_monero_tweak(l1, idx1 & MASK, ax1, bx10, bx11, cx1); } else { _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx00, cx0)); _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx10, cx1)); @@ -616,12 +692,27 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si uint64_t hi, lo, cl, ch; cl = ((uint64_t*) &l0[idx0 & MASK])[0]; ch = ((uint64_t*) &l0[idx0 & MASK])[1]; - if (VARIANT == xmrig::VARIANT_2) { - VARIANT2_INTEGER_MATH(0, cl, cx0); - lo = __umul128(idx0, cl, &hi); - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo); - } else { - lo = __umul128(idx0, cl, &hi); + + if (BASE == xmrig::VARIANT_2) { + if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + VARIANT4_RANDOM_MATH(0, al0, ah0, cl, bx00, bx01); + if (VARIANT == xmrig::VARIANT_4) { + al0 ^= r0[2] | ((uint64_t)(r0[3]) << 32); + ah0 ^= r0[0] | ((uint64_t)(r0[1]) << 32); + } + } else { + VARIANT2_INTEGER_MATH(0, cl, cx0); + } + } + + lo = __umul128(idx0, cl, &hi); + + if (BASE == xmrig::VARIANT_2) { + if (VARIANT == xmrig::VARIANT_4) { + VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx00, bx01, cx0); + } else { + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo); + } } al0 += hi; @@ -629,9 +720,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l0[idx0 & MASK])[0] = al0; - if (IS_V1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; - } else if (IS_V1) { + } else if (BASE == xmrig::VARIANT_1) { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; } else { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0; @@ -641,7 +732,7 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ah0 ^= ch; idx0 = al0; - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { const int64x2_t x = vld1q_s64(reinterpret_cast(&l0[idx0 & MASK])); const int64_t n = vgetq_lane_s64(x, 0); const int32_t d = vgetq_lane_s32(x, 2); @@ -659,12 +750,27 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si cl = ((uint64_t*) &l1[idx1 & MASK])[0]; ch = ((uint64_t*) &l1[idx1 & MASK])[1]; - if (VARIANT == xmrig::VARIANT_2) { - VARIANT2_INTEGER_MATH(1, cl, cx1); - lo = __umul128(idx1, cl, &hi); - VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo); - } else { - lo = __umul128(idx1, cl, &hi); + + if (BASE == xmrig::VARIANT_2) { + if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + VARIANT4_RANDOM_MATH(1, al1, ah1, cl, bx10, bx11); + if (VARIANT == xmrig::VARIANT_4) { + al1 ^= r1[2] | ((uint64_t)(r1[3]) << 32); + ah1 ^= r1[0] | ((uint64_t)(r1[1]) << 32); + } + } else { + VARIANT2_INTEGER_MATH(1, cl, cx1); + } + } + + lo = __umul128(idx1, cl, &hi); + + if (BASE == xmrig::VARIANT_2) { + if (VARIANT == xmrig::VARIANT_4) { + VARIANT2_SHUFFLE(l1, idx1 & MASK, ax1, bx10, bx11, cx1); + } else { + VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo); + } } al1 += hi; @@ -672,9 +778,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l1[idx1 & MASK])[0] = al1; - if (IS_V1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1 ^ al1; - } else if (IS_V1) { + } else if (BASE == xmrig::VARIANT_1) { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1; } else { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1; @@ -699,7 +805,7 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si idx1 = d ^ q; } } - if (VARIANT == xmrig::VARIANT_2) { + if (BASE == xmrig::VARIANT_2) { bx01 = bx00; bx11 = bx10; } @@ -719,19 +825,19 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si template -inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx) +inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx, uint64_t height) { } template -inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx) +inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx, uint64_t height) { } template -inline void cryptonight_penta_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx) +inline void cryptonight_penta_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx, uint64_t height) { } diff --git a/src/Native/libcryptonight/crypto/CryptoNight_constants.h b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_constants.h similarity index 69% rename from src/Native/libcryptonight/crypto/CryptoNight_constants.h rename to src/Native/libcryptonight/xmrig/crypto/CryptoNight_constants.h index f13891a76..4ea1adb3b 100644 --- a/src/Native/libcryptonight/crypto/CryptoNight_constants.h +++ b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_constants.h @@ -4,9 +4,10 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , + * Copyright 2017-2019 XMR-Stak , * Copyright 2018 Lee Clagett - * Copyright 2016-2018 XMRig , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,10 +23,11 @@ * along with this program. If not, see . */ -#ifndef __CRYPTONIGHT_CONSTANTS_H__ -#define __CRYPTONIGHT_CONSTANTS_H__ +#ifndef XMRIG_CRYPTONIGHT_CONSTANTS_H +#define XMRIG_CRYPTONIGHT_CONSTANTS_H +#include #include @@ -38,9 +40,12 @@ namespace xmrig constexpr const size_t CRYPTONIGHT_MEMORY = 2 * 1024 * 1024; constexpr const uint32_t CRYPTONIGHT_MASK = 0x1FFFF0; constexpr const uint32_t CRYPTONIGHT_ITER = 0x80000; -constexpr const uint32_t CRYPTONIGHT_MSR_ITER = 0x40000; +constexpr const uint32_t CRYPTONIGHT_HALF_ITER = 0x40000; constexpr const uint32_t CRYPTONIGHT_XAO_ITER = 0x100000; +constexpr const uint32_t CRYPTONIGHT_GPU_ITER = 0xC000; +constexpr const uint32_t CRYPTONIGHT_GPU_MASK = 0x1FFFC0; + constexpr const size_t CRYPTONIGHT_LITE_MEMORY = 1 * 1024 * 1024; constexpr const uint32_t CRYPTONIGHT_LITE_MASK = 0xFFFF0; constexpr const uint32_t CRYPTONIGHT_LITE_ITER = 0x40000; @@ -49,11 +54,17 @@ constexpr const size_t CRYPTONIGHT_HEAVY_MEMORY = 4 * 1024 * 1024; constexpr const uint32_t CRYPTONIGHT_HEAVY_MASK = 0x3FFFF0; constexpr const uint32_t CRYPTONIGHT_HEAVY_ITER = 0x40000; +constexpr const size_t CRYPTONIGHT_PICO_MEMORY = 256 * 1024; +constexpr const uint32_t CRYPTONIGHT_PICO_MASK = 0x1FFF0; +constexpr const uint32_t CRYPTONIGHT_PICO_ITER = 0x40000; +constexpr const uint32_t CRYPTONIGHT_TRTL_ITER = 0x10000; + template inline constexpr size_t cn_select_memory() { return 0; } template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_MEMORY; } template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_LITE_MEMORY; } template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_HEAVY_MEMORY; } +template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_PICO_MEMORY; } inline size_t cn_select_memory(Algo algorithm) @@ -69,6 +80,9 @@ inline size_t cn_select_memory(Algo algorithm) case CRYPTONIGHT_HEAVY: return CRYPTONIGHT_HEAVY_MEMORY; + case CRYPTONIGHT_PICO: + return CRYPTONIGHT_PICO_MEMORY; + default: break; } @@ -81,6 +95,7 @@ template inline constexpr uint32_t cn_select_mask() { retur template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_MASK; } template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_LITE_MASK; } template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_HEAVY_MASK; } +template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_PICO_MASK; } inline uint32_t cn_select_mask(Algo algorithm) @@ -96,6 +111,9 @@ inline uint32_t cn_select_mask(Algo algorithm) case CRYPTONIGHT_HEAVY: return CRYPTONIGHT_HEAVY_MASK; + case CRYPTONIGHT_PICO: + return CRYPTONIGHT_PICO_MASK; + default: break; } @@ -108,26 +126,38 @@ template inline constexpr uint32_t cn_select_iter() template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_MSR_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HALF_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HALF_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_XAO_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_GPU_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_TRTL_ITER; } inline uint32_t cn_select_iter(Algo algorithm, Variant variant) { switch (variant) { case VARIANT_MSR: - return CRYPTONIGHT_MSR_ITER; + case VARIANT_HALF: + return CRYPTONIGHT_HALF_ITER; + + case VARIANT_GPU: + return CRYPTONIGHT_GPU_ITER; case VARIANT_RTO: return CRYPTONIGHT_XAO_ITER; + case VARIANT_TRTL: + return CRYPTONIGHT_TRTL_ITER; + default: break; } @@ -143,6 +173,9 @@ inline uint32_t cn_select_iter(Algo algorithm, Variant variant) case CRYPTONIGHT_HEAVY: return CRYPTONIGHT_HEAVY_ITER; + case CRYPTONIGHT_PICO: + return CRYPTONIGHT_TRTL_ITER; + default: break; } @@ -161,9 +194,18 @@ template<> inline constexpr Variant cn_base_variant() { return VA template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_GPU; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } + +template inline constexpr bool cn_is_cryptonight_r() { return false; } +template<> inline constexpr bool cn_is_cryptonight_r() { return true; } +template<> inline constexpr bool cn_is_cryptonight_r() { return true; } } /* namespace xmrig */ -#endif /* __CRYPTONIGHT_CONSTANTS_H__ */ +#endif /* XMRIG_CRYPTONIGHT_CONSTANTS_H */ diff --git a/src/Native/libcryptonight/crypto/CryptoNight_monero.h b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_monero.h similarity index 78% rename from src/Native/libcryptonight/crypto/CryptoNight_monero.h rename to src/Native/libcryptonight/xmrig/crypto/CryptoNight_monero.h index 522290268..26c1fff0e 100644 --- a/src/Native/libcryptonight/crypto/CryptoNight_monero.h +++ b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_monero.h @@ -7,7 +7,7 @@ * Copyright 2017-2018 XMR-Stak , * Copyright 2018 Lee Clagett * Copyright 2018 SChernykh - * Copyright 2016-2018 XMRig , + * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,21 +33,21 @@ #ifndef XMRIG_ARM # define VARIANT1_INIT(part) \ uint64_t tweak1_2_##part = 0; \ - if (IS_V1) { \ + if (BASE == xmrig::VARIANT_1) { \ tweak1_2_##part = (*reinterpret_cast(input + 35 + part * size) ^ \ *(reinterpret_cast(ctx[part]->state) + 24)); \ } #else # define VARIANT1_INIT(part) \ uint64_t tweak1_2_##part = 0; \ - if (IS_V1) { \ + if (BASE == xmrig::VARIANT_1) { \ memcpy(&tweak1_2_##part, input + 35 + part * size, sizeof tweak1_2_##part); \ tweak1_2_##part ^= *(reinterpret_cast(ctx[part]->state) + 24); \ } #endif #define VARIANT1_1(p) \ - if (IS_V1) { \ + if (BASE == xmrig::VARIANT_1) { \ const uint8_t tmp = reinterpret_cast(p)[11]; \ static const uint32_t table = 0x75310; \ const uint8_t index = (((tmp >> 3) & 6) | (tmp & 1)) << 1; \ @@ -55,7 +55,7 @@ } #define VARIANT1_2(p, part) \ - if (IS_V1) { \ + if (BASE == xmrig::VARIANT_1) { \ (p) ^= tweak1_2_##part; \ } @@ -66,9 +66,9 @@ __m128i sqrt_result_xmm_##part = _mm_cvtsi64_si128(h##part[13]); #ifdef _MSC_VER -# define VARIANT2_SET_ROUNDING_MODE() if (VARIANT == xmrig::VARIANT_2) { _control87(RC_DOWN, MCW_RC); } +# define VARIANT2_SET_ROUNDING_MODE() if (BASE == xmrig::VARIANT_2) { _control87(RC_DOWN, MCW_RC); } #else -# define VARIANT2_SET_ROUNDING_MODE() if (VARIANT == xmrig::VARIANT_2) { fesetround(FE_DOWNWARD); } +# define VARIANT2_SET_ROUNDING_MODE() if (BASE == xmrig::VARIANT_2) { fesetround(FE_DOWNWARD); } #endif # define VARIANT2_INTEGER_MATH(part, cl, cx) \ @@ -83,7 +83,7 @@ sqrt_result_xmm_##part = int_sqrt_v2(cx_0 + division_result); \ } while (0) -# define VARIANT2_SHUFFLE(base_ptr, offset, _a, _b, _b1) \ +# define VARIANT2_SHUFFLE(base_ptr, offset, _a, _b, _b1, _c) \ do { \ const __m128i chunk1 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10))); \ const __m128i chunk2 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20))); \ @@ -91,6 +91,9 @@ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10)), _mm_add_epi64(chunk3, _b1)); \ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20)), _mm_add_epi64(chunk1, _b)); \ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30)), _mm_add_epi64(chunk2, _a)); \ + if (VARIANT == xmrig::VARIANT_4) { \ + _c = _mm_xor_si128(_mm_xor_si128(_c, chunk3), _mm_xor_si128(chunk1, chunk2)); \ + } \ } while (0) # define VARIANT2_SHUFFLE2(base_ptr, offset, _a, _b, _b1, hi, lo) \ @@ -125,7 +128,7 @@ sqrt_result_##part += ((r2 + b > sqrt_input) ? -1 : 0) + ((r2 + (1ULL << 32) < sqrt_input - s) ? 1 : 0); \ } while (0) -# define VARIANT2_SHUFFLE(base_ptr, offset, _a, _b, _b1) \ +# define VARIANT2_SHUFFLE(base_ptr, offset, _a, _b, _b1, _c) \ do { \ const uint64x2_t chunk1 = vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10))); \ const uint64x2_t chunk2 = vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20))); \ @@ -133,6 +136,9 @@ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10)), vaddq_u64(chunk3, vreinterpretq_u64_u8(_b1))); \ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20)), vaddq_u64(chunk1, vreinterpretq_u64_u8(_b))); \ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x30)), vaddq_u64(chunk2, vreinterpretq_u64_u8(_a))); \ + if (VARIANT == xmrig::VARIANT_4) { \ + _c = veorq_u64(veorq_u64(_c, chunk3), veorq_u64(chunk1, chunk2)); \ + } \ } while (0) # define VARIANT2_SHUFFLE2(base_ptr, offset, _a, _b, _b1, hi, lo) \ @@ -147,4 +153,34 @@ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x30)), vaddq_u64(chunk2, vreinterpretq_u64_u8(_a))); \ } while (0) #endif + +#define SWAP32LE(x) x +#define SWAP64LE(x) x +#define hash_extra_blake(data, length, hash) blake256_hash((uint8_t*)(hash), (uint8_t*)(data), (length)) + +#include "common/xmrig.h" +#include "variant4_random_math.h" + +#define VARIANT4_RANDOM_MATH_INIT(part) \ + uint32_t r##part[9]; \ + struct V4_Instruction code##part[256]; \ + if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { \ + r##part[0] = (uint32_t)(h##part[12]); \ + r##part[1] = (uint32_t)(h##part[12] >> 32); \ + r##part[2] = (uint32_t)(h##part[13]); \ + r##part[3] = (uint32_t)(h##part[13] >> 32); \ + } \ + v4_random_math_init(code##part, height); + +#define VARIANT4_RANDOM_MATH(part, al, ah, cl, bx0, bx1) \ + if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { \ + cl ^= (r##part[0] + r##part[1]) | ((uint64_t)(r##part[2] + r##part[3]) << 32); \ + r##part[4] = static_cast(al); \ + r##part[5] = static_cast(ah); \ + r##part[6] = static_cast(_mm_cvtsi128_si32(bx0)); \ + r##part[7] = static_cast(_mm_cvtsi128_si32(bx1)); \ + r##part[8] = static_cast(_mm_cvtsi128_si32(_mm_srli_si128(bx1, 8))); \ + v4_random_math(code##part, r##part); \ + } + #endif /* XMRIG_CRYPTONIGHT_MONERO_H */ diff --git a/src/Native/libcryptonight/crypto/CryptoNight_x86.h b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_x86.h similarity index 73% rename from src/Native/libcryptonight/crypto/CryptoNight_x86.h rename to src/Native/libcryptonight/xmrig/crypto/CryptoNight_x86.h index 8dcdd4144..4c5d4ac04 100644 --- a/src/Native/libcryptonight/crypto/CryptoNight_x86.h +++ b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_x86.h @@ -4,10 +4,10 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , + * Copyright 2017-2019 XMR-Stak , * Copyright 2018 Lee Clagett - * Copyright 2018 SChernykh - * Copyright 2016-2018 XMRig , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,6 +35,7 @@ #endif +#include "common/cpu/Cpu.h" #include "common/crypto/keccak.h" #include "crypto/CryptoNight.h" #include "crypto/CryptoNight_constants.h" @@ -289,6 +290,34 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) } +#ifndef XMRIG_NO_CN_GPU +template +void cn_explode_scratchpad_gpu(const uint8_t *input, uint8_t *output) +{ + constexpr size_t hash_size = 200; // 25x8 bytes + alignas(16) uint64_t hash[25]; + + for (uint64_t i = 0; i < MEM / 512; i++) + { + memcpy(hash, input, hash_size); + hash[0] ^= i; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 160); + output += 160; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 176); + output += 176; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 176); + output += 176; + } +} +#endif + + template static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) { @@ -427,11 +456,11 @@ static inline __m128i int_sqrt_v2(const uint64_t n0) } -template -static inline void cryptonight_monero_tweak(uint64_t* mem_out, const uint8_t* l, uint64_t idx, __m128i ax0, __m128i bx0, __m128i bx1, __m128i cx) +template +static inline void cryptonight_monero_tweak(uint64_t* mem_out, const uint8_t* l, uint64_t idx, __m128i ax0, __m128i bx0, __m128i bx1, __m128i& cx) { - if (VARIANT == xmrig::VARIANT_2) { - VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1); + if (BASE == xmrig::VARIANT_2) { + VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1, cx); _mm_store_si128((__m128i *)mem_out, _mm_xor_si128(bx0, cx)); } else { __m128i tmp = _mm_xor_si128(bx0, cx); @@ -451,14 +480,16 @@ static inline void cryptonight_monero_tweak(uint64_t* mem_out, const uint8_t* l, template -inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr bool IS_V1 = xmrig::cn_base_variant() == xmrig::VARIANT_1; + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); - if (IS_V1 && size < 43) { + static_assert(MASK > 0 && ITERATIONS > 0 && MEM > 0, "unsupported algorithm/variant"); + + if (BASE == xmrig::VARIANT_1 && size < 43) { memset(output, 0, 32); return; } @@ -473,6 +504,7 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si VARIANT1_INIT(0); VARIANT2_INIT(0); VARIANT2_SET_ROUNDING_MODE(); + VARIANT4_RANDOM_MATH_INIT(0); uint64_t al0 = h0[0] ^ h0[4]; uint64_t ah0 = h0[1] ^ h0[5]; @@ -494,12 +526,12 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si else if (SOFT_AES) { cx = soft_aesenc((uint32_t*)&l0[idx0 & MASK], ax0); } - else { + else { cx = _mm_aesenc_si128(cx, ax0); } - if (IS_V1 || VARIANT == xmrig::VARIANT_2) { - cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], l0, idx0 & MASK, ax0, bx0, bx1, cx); + if (BASE == xmrig::VARIANT_1 || BASE == xmrig::VARIANT_2) { + cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], l0, idx0 & MASK, ax0, bx0, bx1, cx); } else { _mm_store_si128((__m128i *)&l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); } @@ -509,13 +541,27 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si uint64_t hi, lo, cl, ch; cl = ((uint64_t*) &l0[idx0 & MASK])[0]; ch = ((uint64_t*) &l0[idx0 & MASK])[1]; - if (VARIANT == xmrig::VARIANT_2) { - VARIANT2_INTEGER_MATH(0, cl, cx); - lo = __umul128(idx0, cl, &hi); - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo); + + if (BASE == xmrig::VARIANT_2) { + if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + VARIANT4_RANDOM_MATH(0, al0, ah0, cl, bx0, bx1); + if (VARIANT == xmrig::VARIANT_4) { + al0 ^= r0[2] | ((uint64_t)(r0[3]) << 32); + ah0 ^= r0[0] | ((uint64_t)(r0[1]) << 32); + } + } else { + VARIANT2_INTEGER_MATH(0, cl, cx); + } } - else { - lo = __umul128(idx0, cl, &hi); + + lo = __umul128(idx0, cl, &hi); + + if (BASE == xmrig::VARIANT_2) { + if (VARIANT == xmrig::VARIANT_4) { + VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx0, bx1, cx); + } else { + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo); + } } al0 += hi; @@ -523,9 +569,9 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l0[idx0 & MASK])[0] = al0; - if (IS_V1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; - } else if (IS_V1) { + } else if (BASE == xmrig::VARIANT_1) { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; } else { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0; @@ -548,9 +594,11 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si idx0 = d ^ q; } - if (VARIANT == xmrig::VARIANT_2) { + + if (BASE == xmrig::VARIANT_2) { bx1 = bx0; } + bx0 = cx; } @@ -561,25 +609,143 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si } +#ifndef XMRIG_NO_CN_GPU +template +void cn_gpu_inner_avx(const uint8_t *spad, uint8_t *lpad); + + +template +void cn_gpu_inner_ssse3(const uint8_t *spad, uint8_t *lpad); + + +template +inline void cryptonight_single_hash_gpu(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) +{ + constexpr size_t MASK = xmrig::CRYPTONIGHT_GPU_MASK; + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + + static_assert(MASK > 0 && ITERATIONS > 0 && MEM > 0, "unsupported algorithm/variant"); + + xmrig::keccak(input, size, ctx[0]->state); + cn_explode_scratchpad_gpu(ctx[0]->state, ctx[0]->memory); + +# ifdef _MSC_VER + _control87(RC_NEAR, MCW_RC); +# else + fesetround(FE_TONEAREST); +# endif + + if (xmrig::Cpu::info()->hasAVX2()) { + cn_gpu_inner_avx(ctx[0]->state, ctx[0]->memory); + } else { + cn_gpu_inner_ssse3(ctx[0]->state, ctx[0]->memory); + } + + cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); + + xmrig::keccakf((uint64_t*) ctx[0]->state, 24); + memcpy(output, ctx[0]->state, 32); +} +#endif + + #ifndef XMRIG_NO_ASM extern "C" void cnv2_mainloop_ivybridge_asm(cryptonight_ctx *ctx); extern "C" void cnv2_mainloop_ryzen_asm(cryptonight_ctx *ctx); +extern "C" void cnv2_mainloop_bulldozer_asm(cryptonight_ctx *ctx); extern "C" void cnv2_double_mainloop_sandybridge_asm(cryptonight_ctx* ctx0, cryptonight_ctx* ctx1); +extern xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_ivybridge_asm; +extern xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_ryzen_asm; +extern xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_bulldozer_asm; +extern xmrig::CpuThread::cn_mainloop_double_fun cn_half_double_mainloop_sandybridge_asm; + +extern xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_ivybridge_asm; +extern xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_ryzen_asm; +extern xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_bulldozer_asm; +extern xmrig::CpuThread::cn_mainloop_double_fun cn_trtl_double_mainloop_sandybridge_asm; + +void wow_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); +void v4_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); +void wow_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); +void v4_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); + +template +void cn_r_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) +{ + v4_compile_code(code, code_size, machine_code, ASM); +} + +template +void cn_r_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) +{ + v4_compile_code_double(code, code_size, machine_code, ASM); +} + +template<> +void cn_r_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) +{ + wow_compile_code(code, code_size, machine_code, ASM); +} + +template<> +void cn_r_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) +{ + wow_compile_code_double(code, code_size, machine_code, ASM); +} template -inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { constexpr size_t MEM = xmrig::cn_select_memory(); + if (xmrig::cn_is_cryptonight_r() && !ctx[0]->generated_code_data.match(VARIANT, height)) { + V4_Instruction code[256]; + const int code_size = v4_random_math_init(code, height); + cn_r_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), ASM); + ctx[0]->generated_code_data.variant = VARIANT; + ctx[0]->generated_code_data.height = height; + } + xmrig::keccak(input, size, ctx[0]->state); cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->state), reinterpret_cast<__m128i*>(ctx[0]->memory)); - if (ASM == xmrig::ASM_INTEL) { - cnv2_mainloop_ivybridge_asm(ctx[0]); + if (VARIANT == xmrig::VARIANT_2) { + if (ASM == xmrig::ASM_INTEL) { + cnv2_mainloop_ivybridge_asm(ctx[0]); + } + else if (ASM == xmrig::ASM_RYZEN) { + cnv2_mainloop_ryzen_asm(ctx[0]); + } + else { + cnv2_mainloop_bulldozer_asm(ctx[0]); + } } - else { - cnv2_mainloop_ryzen_asm(ctx[0]); + else if (VARIANT == xmrig::VARIANT_HALF) { + if (ASM == xmrig::ASM_INTEL) { + cn_half_mainloop_ivybridge_asm(ctx[0]); + } + else if (ASM == xmrig::ASM_RYZEN) { + cn_half_mainloop_ryzen_asm(ctx[0]); + } + else { + cn_half_mainloop_bulldozer_asm(ctx[0]); + } + } + else if (VARIANT == xmrig::VARIANT_TRTL) { + if (ASM == xmrig::ASM_INTEL) { + cn_trtl_mainloop_ivybridge_asm(ctx[0]); + } + else if (ASM == xmrig::ASM_RYZEN) { + cn_trtl_mainloop_ryzen_asm(ctx[0]); + } + else { + cn_trtl_mainloop_bulldozer_asm(ctx[0]); + } + } + else if (xmrig::cn_is_cryptonight_r()) { + ctx[0]->generated_code(ctx[0]); } cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->memory), reinterpret_cast<__m128i*>(ctx[0]->state)); @@ -589,17 +755,36 @@ inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_ template -inline void cryptonight_double_hash_asm(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +inline void cryptonight_double_hash_asm(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { constexpr size_t MEM = xmrig::cn_select_memory(); + if (xmrig::cn_is_cryptonight_r() && !ctx[0]->generated_code_double_data.match(VARIANT, height)) { + V4_Instruction code[256]; + const int code_size = v4_random_math_init(code, height); + cn_r_compile_code_double(code, code_size, reinterpret_cast(ctx[0]->generated_code_double), ASM); + ctx[0]->generated_code_double_data.variant = VARIANT; + ctx[0]->generated_code_double_data.height = height; + } + xmrig::keccak(input, size, ctx[0]->state); xmrig::keccak(input + size, size, ctx[1]->state); cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->state), reinterpret_cast<__m128i*>(ctx[0]->memory)); cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[1]->state), reinterpret_cast<__m128i*>(ctx[1]->memory)); - cnv2_double_mainloop_sandybridge_asm(ctx[0], ctx[1]); + if (VARIANT == xmrig::VARIANT_2) { + cnv2_double_mainloop_sandybridge_asm(ctx[0], ctx[1]); + } + else if (VARIANT == xmrig::VARIANT_HALF) { + cn_half_double_mainloop_sandybridge_asm(ctx[0], ctx[1]); + } + else if (VARIANT == xmrig::VARIANT_TRTL) { + cn_trtl_double_mainloop_sandybridge_asm(ctx[0], ctx[1]); + } + else if (xmrig::cn_is_cryptonight_r()) { + ctx[0]->generated_code_double(ctx[0], ctx[1]); + } cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->memory), reinterpret_cast<__m128i*>(ctx[0]->state)); cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[1]->memory), reinterpret_cast<__m128i*>(ctx[1]->state)); @@ -614,14 +799,14 @@ inline void cryptonight_double_hash_asm(const uint8_t *__restrict__ input, size_ template -inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr bool IS_V1 = xmrig::cn_base_variant() == xmrig::VARIANT_1; + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); - if (IS_V1 && size < 43) { + if (BASE == xmrig::VARIANT_1 && size < 43) { memset(output, 0, 64); return; } @@ -639,6 +824,8 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si VARIANT2_INIT(0); VARIANT2_INIT(1); VARIANT2_SET_ROUNDING_MODE(); + VARIANT4_RANDOM_MATH_INIT(0); + VARIANT4_RANDOM_MATH_INIT(1); cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0); cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1); @@ -678,9 +865,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si cx1 = _mm_aesenc_si128(cx1, ax1); } - if (IS_V1 || (VARIANT == xmrig::VARIANT_2)) { - cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], l0, idx0 & MASK, ax0, bx00, bx01, cx0); - cryptonight_monero_tweak((uint64_t*)&l1[idx1 & MASK], l1, idx1 & MASK, ax1, bx10, bx11, cx1); + if (BASE == xmrig::VARIANT_1 || (BASE == xmrig::VARIANT_2)) { + cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], l0, idx0 & MASK, ax0, bx00, bx01, cx0); + cryptonight_monero_tweak((uint64_t*)&l1[idx1 & MASK], l1, idx1 & MASK, ax1, bx10, bx11, cx1); } else { _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx00, cx0)); _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx10, cx1)); @@ -692,12 +879,27 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si uint64_t hi, lo, cl, ch; cl = ((uint64_t*) &l0[idx0 & MASK])[0]; ch = ((uint64_t*) &l0[idx0 & MASK])[1]; - if (VARIANT == xmrig::VARIANT_2) { - VARIANT2_INTEGER_MATH(0, cl, cx0); - lo = __umul128(idx0, cl, &hi); - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo); - } else { - lo = __umul128(idx0, cl, &hi); + + if (BASE == xmrig::VARIANT_2) { + if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + VARIANT4_RANDOM_MATH(0, al0, ah0, cl, bx00, bx01); + if (VARIANT == xmrig::VARIANT_4) { + al0 ^= r0[2] | ((uint64_t)(r0[3]) << 32); + ah0 ^= r0[0] | ((uint64_t)(r0[1]) << 32); + } + } else { + VARIANT2_INTEGER_MATH(0, cl, cx0); + } + } + + lo = __umul128(idx0, cl, &hi); + + if (BASE == xmrig::VARIANT_2) { + if (VARIANT == xmrig::VARIANT_4) { + VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx00, bx01, cx0); + } else { + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo); + } } al0 += hi; @@ -705,9 +907,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l0[idx0 & MASK])[0] = al0; - if (IS_V1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { ((uint64_t*) &l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; - } else if (IS_V1) { + } else if (BASE == xmrig::VARIANT_1) { ((uint64_t*) &l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; } else { ((uint64_t*) &l0[idx0 & MASK])[1] = ah0; @@ -733,12 +935,27 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si cl = ((uint64_t*) &l1[idx1 & MASK])[0]; ch = ((uint64_t*) &l1[idx1 & MASK])[1]; - if (VARIANT == xmrig::VARIANT_2) { - VARIANT2_INTEGER_MATH(1, cl, cx1); - lo = __umul128(idx1, cl, &hi); - VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo); - } else { - lo = __umul128(idx1, cl, &hi); + + if (BASE == xmrig::VARIANT_2) { + if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + VARIANT4_RANDOM_MATH(1, al1, ah1, cl, bx10, bx11); + if (VARIANT == xmrig::VARIANT_4) { + al1 ^= r1[2] | ((uint64_t)(r1[3]) << 32); + ah1 ^= r1[0] | ((uint64_t)(r1[1]) << 32); + } + } else { + VARIANT2_INTEGER_MATH(1, cl, cx1); + } + } + + lo = __umul128(idx1, cl, &hi); + + if (BASE == xmrig::VARIANT_2) { + if (VARIANT == xmrig::VARIANT_4) { + VARIANT2_SHUFFLE(l1, idx1 & MASK, ax1, bx10, bx11, cx1); + } else { + VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo); + } } al1 += hi; @@ -746,9 +963,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l1[idx1 & MASK])[0] = al1; - if (IS_V1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1 ^ al1; - } else if (IS_V1) { + } else if (BASE == xmrig::VARIANT_1) { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1; } else { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1; @@ -772,10 +989,11 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si idx1 = d ^ q; } - if (VARIANT == xmrig::VARIANT_2) { + if (BASE == xmrig::VARIANT_2) { bx01 = bx00; bx11 = bx10; } + bx00 = cx0; bx10 = cx1; } @@ -806,8 +1024,8 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si c = _mm_aesenc_si128(c, a); \ } \ \ - if (IS_V1 || (VARIANT == xmrig::VARIANT_2)) { \ - cryptonight_monero_tweak((uint64_t*)ptr, l, idx & MASK, a, b0, b1, c); \ + if (BASE == xmrig::VARIANT_1 || BASE == xmrig::VARIANT_2) { \ + cryptonight_monero_tweak((uint64_t*)ptr, l, idx & MASK, a, b0, b1, c); \ } else { \ _mm_store_si128(ptr, _mm_xor_si128(b0, c)); \ } @@ -821,16 +1039,34 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si #define CN_STEP4(part, a, b0, b1, c, l, mc, ptr, idx) \ - if (VARIANT == xmrig::VARIANT_2) { \ - VARIANT2_INTEGER_MATH(part, cl##part, c); \ - lo = __umul128(idx, cl##part, &hi); \ - VARIANT2_SHUFFLE2(l, idx & MASK, a, b0, b1, hi, lo); \ - } else { \ - lo = __umul128(idx, cl##part, &hi); \ + uint64_t al##part, ah##part; \ + if (BASE == xmrig::VARIANT_2) { \ + if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { \ + al##part = _mm_cvtsi128_si64(a); \ + ah##part = _mm_cvtsi128_si64(_mm_srli_si128(a, 8)); \ + VARIANT4_RANDOM_MATH(part, al##part, ah##part, cl##part, b0, b1); \ + if (VARIANT == xmrig::VARIANT_4) { \ + al##part ^= r##part[2] | ((uint64_t)(r##part[3]) << 32); \ + ah##part ^= r##part[0] | ((uint64_t)(r##part[1]) << 32); \ + } \ + } else { \ + VARIANT2_INTEGER_MATH(part, cl##part, c); \ + } \ + } \ + lo = __umul128(idx, cl##part, &hi); \ + if (BASE == xmrig::VARIANT_2) { \ + if (VARIANT == xmrig::VARIANT_4) { \ + VARIANT2_SHUFFLE(l, idx & MASK, a, b0, b1, c); \ + } else { \ + VARIANT2_SHUFFLE2(l, idx & MASK, a, b0, b1, hi, lo); \ + } \ + } \ + if (VARIANT == xmrig::VARIANT_4) { \ + a = _mm_set_epi64x(ah##part, al##part); \ } \ a = _mm_add_epi64(a, _mm_set_epi64x(lo, hi)); \ \ - if (IS_V1) { \ + if (BASE == xmrig::VARIANT_1) { \ _mm_store_si128(ptr, _mm_xor_si128(a, mc)); \ \ if (VARIANT == xmrig::VARIANT_TUBE || \ @@ -855,7 +1091,7 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si \ idx = d ^ q; \ } \ - if (VARIANT == xmrig::VARIANT_2) { \ + if (BASE == xmrig::VARIANT_2) { \ b1 = b0; \ } \ b0 = c; @@ -865,29 +1101,30 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si __m128i mc##n; \ __m128i division_result_xmm_##n; \ __m128i sqrt_result_xmm_##n; \ - if (IS_V1) { \ + if (BASE == xmrig::VARIANT_1) { \ mc##n = _mm_set_epi64x(*reinterpret_cast(input + n * size + 35) ^ \ *(reinterpret_cast((ctx)->state) + 24), 0); \ } \ - if (VARIANT == xmrig::VARIANT_2) { \ + if (BASE == xmrig::VARIANT_2) { \ division_result_xmm_##n = _mm_cvtsi64_si128(h##n[12]); \ sqrt_result_xmm_##n = _mm_cvtsi64_si128(h##n[13]); \ } \ __m128i ax##n = _mm_set_epi64x(h##n[1] ^ h##n[5], h##n[0] ^ h##n[4]); \ __m128i bx##n##0 = _mm_set_epi64x(h##n[3] ^ h##n[7], h##n[2] ^ h##n[6]); \ __m128i bx##n##1 = _mm_set_epi64x(h##n[9] ^ h##n[11], h##n[8] ^ h##n[10]); \ - __m128i cx##n = _mm_setzero_si128(); + __m128i cx##n = _mm_setzero_si128(); \ + VARIANT4_RANDOM_MATH_INIT(n); template -inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr bool IS_V1 = xmrig::cn_base_variant() == xmrig::VARIANT_1; + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); - if (IS_V1 && size < 43) { + if (BASE == xmrig::VARIANT_1 && size < 43) { memset(output, 0, 32 * 3); return; } @@ -944,14 +1181,14 @@ inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t si template -inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr bool IS_V1 = xmrig::cn_base_variant() == xmrig::VARIANT_1;; + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); - if (IS_V1 && size < 43) { + if (BASE == xmrig::VARIANT_1 && size < 43) { memset(output, 0, 32 * 4); return; } @@ -1017,14 +1254,14 @@ inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size template -inline void cryptonight_penta_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +inline void cryptonight_penta_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr bool IS_V1 = xmrig::cn_base_variant() == xmrig::VARIANT_1; + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); - if (IS_V1 && size < 43) { + if (BASE == xmrig::VARIANT_1 && size < 43) { memset(output, 0, 32 * 5); return; } diff --git a/src/Native/libcryptonight/xmrig/crypto/CryptonightR_gen.cpp b/src/Native/libcryptonight/xmrig/crypto/CryptonightR_gen.cpp new file mode 100644 index 000000000..55f94662c --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/CryptonightR_gen.cpp @@ -0,0 +1,162 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "crypto/CryptoNight_monero.h" + +typedef void(*void_func)(); + +#include "crypto/asm/CryptonightR_template.h" +#include "Mem.h" + +#if !defined XMRIG_ARM && !defined XMRIG_NO_ASM + +static inline void add_code(uint8_t* &p, void (*p1)(), void (*p2)()) +{ + const ptrdiff_t size = reinterpret_cast(p2) - reinterpret_cast(p1); + if (size > 0) { + memcpy(p, reinterpret_cast(p1), size); + p += size; + } +} + +static inline void add_random_math(uint8_t* &p, const V4_Instruction* code, int code_size, const void_func* instructions, const void_func* instructions_mov, bool is_64_bit, xmrig::Assembly ASM) +{ + uint32_t prev_rot_src = (uint32_t)(-1); + + for (int i = 0;; ++i) { + const V4_Instruction inst = code[i]; + if (inst.opcode == RET) { + break; + } + + uint8_t opcode = (inst.opcode == MUL) ? inst.opcode : (inst.opcode + 2); + uint8_t dst_index = inst.dst_index; + uint8_t src_index = inst.src_index; + + const uint32_t a = inst.dst_index; + const uint32_t b = inst.src_index; + const uint8_t c = opcode | (dst_index << V4_OPCODE_BITS) | (((src_index == 8) ? dst_index : src_index) << (V4_OPCODE_BITS + V4_DST_INDEX_BITS)); + + switch (inst.opcode) { + case ROR: + case ROL: + if (b != prev_rot_src) { + prev_rot_src = b; + add_code(p, instructions_mov[c], instructions_mov[c + 1]); + } + break; + } + + if (a == prev_rot_src) { + prev_rot_src = (uint32_t)(-1); + } + + void_func begin = instructions[c]; + + if ((ASM = xmrig::ASM_BULLDOZER) && (inst.opcode == MUL) && !is_64_bit) { + // AMD Bulldozer has latency 4 for 32-bit IMUL and 6 for 64-bit IMUL + // Always use 32-bit IMUL for AMD Bulldozer in 32-bit mode - skip prefix 0x48 and change 0x49 to 0x41 + uint8_t* prefix = reinterpret_cast(begin); + + if (*prefix == 0x49) { + *(p++) = 0x41; + } + + begin = reinterpret_cast(prefix + 1); + } + + add_code(p, begin, instructions[c + 1]); + + if (inst.opcode == ADD) { + *(uint32_t*)(p - sizeof(uint32_t) - (is_64_bit ? 3 : 0)) = inst.C; + if (is_64_bit) { + prev_rot_src = (uint32_t)(-1); + } + } + } +} + +void wow_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) +{ + uint8_t* p0 = reinterpret_cast(machine_code); + uint8_t* p = p0; + + add_code(p, CryptonightWOW_template_part1, CryptonightWOW_template_part2); + add_random_math(p, code, code_size, instructions, instructions_mov, false, ASM); + add_code(p, CryptonightWOW_template_part2, CryptonightWOW_template_part3); + *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightWOW_template_mainloop) - ((const uint8_t*)CryptonightWOW_template_part1)) - (p - p0)); + add_code(p, CryptonightWOW_template_part3, CryptonightWOW_template_end); + + Mem::flushInstructionCache(machine_code, p - p0); +} + +void v4_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) +{ + uint8_t* p0 = reinterpret_cast(machine_code); + uint8_t* p = p0; + + add_code(p, CryptonightR_template_part1, CryptonightR_template_part2); + add_random_math(p, code, code_size, instructions, instructions_mov, false, ASM); + add_code(p, CryptonightR_template_part2, CryptonightR_template_part3); + *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightR_template_mainloop) - ((const uint8_t*)CryptonightR_template_part1)) - (p - p0)); + add_code(p, CryptonightR_template_part3, CryptonightR_template_end); + + Mem::flushInstructionCache(machine_code, p - p0); +} + +void wow_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) +{ + uint8_t* p0 = reinterpret_cast(machine_code); + uint8_t* p = p0; + + add_code(p, CryptonightWOW_template_double_part1, CryptonightWOW_template_double_part2); + add_random_math(p, code, code_size, instructions, instructions_mov, false, ASM); + add_code(p, CryptonightWOW_template_double_part2, CryptonightWOW_template_double_part3); + add_random_math(p, code, code_size, instructions, instructions_mov, false, ASM); + add_code(p, CryptonightWOW_template_double_part3, CryptonightWOW_template_double_part4); + *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightWOW_template_double_mainloop) - ((const uint8_t*)CryptonightWOW_template_double_part1)) - (p - p0)); + add_code(p, CryptonightWOW_template_double_part4, CryptonightWOW_template_double_end); + + Mem::flushInstructionCache(machine_code, p - p0); +} + +void v4_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) +{ + uint8_t* p0 = reinterpret_cast(machine_code); + uint8_t* p = p0; + + add_code(p, CryptonightR_template_double_part1, CryptonightR_template_double_part2); + add_random_math(p, code, code_size, instructions, instructions_mov, false, ASM); + add_code(p, CryptonightR_template_double_part2, CryptonightR_template_double_part3); + add_random_math(p, code, code_size, instructions, instructions_mov, false, ASM); + add_code(p, CryptonightR_template_double_part3, CryptonightR_template_double_part4); + *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightR_template_double_mainloop) - ((const uint8_t*)CryptonightR_template_double_part1)) - (p - p0)); + add_code(p, CryptonightR_template_double_part4, CryptonightR_template_double_end); + + Mem::flushInstructionCache(machine_code, p - p0); +} + +#endif diff --git a/src/Native/libcryptonight/crypto/SSE2NEON.h b/src/Native/libcryptonight/xmrig/crypto/SSE2NEON.h similarity index 100% rename from src/Native/libcryptonight/crypto/SSE2NEON.h rename to src/Native/libcryptonight/xmrig/crypto/SSE2NEON.h diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.S b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.S new file mode 100644 index 000000000..5f3046cb9 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.S @@ -0,0 +1,1593 @@ +#ifdef __APPLE__ +# define ALIGN(x) .align 6 +#else +# define ALIGN(x) .align 64 +#endif +.intel_syntax noprefix +#ifdef __APPLE__ +# define FN_PREFIX(fn) _ ## fn +.text +#else +# define FN_PREFIX(fn) fn +.section .text +#endif + +#define PUBLIC .global + +PUBLIC FN_PREFIX(CryptonightR_instruction0) +PUBLIC FN_PREFIX(CryptonightR_instruction1) +PUBLIC FN_PREFIX(CryptonightR_instruction2) +PUBLIC FN_PREFIX(CryptonightR_instruction3) +PUBLIC FN_PREFIX(CryptonightR_instruction4) +PUBLIC FN_PREFIX(CryptonightR_instruction5) +PUBLIC FN_PREFIX(CryptonightR_instruction6) +PUBLIC FN_PREFIX(CryptonightR_instruction7) +PUBLIC FN_PREFIX(CryptonightR_instruction8) +PUBLIC FN_PREFIX(CryptonightR_instruction9) +PUBLIC FN_PREFIX(CryptonightR_instruction10) +PUBLIC FN_PREFIX(CryptonightR_instruction11) +PUBLIC FN_PREFIX(CryptonightR_instruction12) +PUBLIC FN_PREFIX(CryptonightR_instruction13) +PUBLIC FN_PREFIX(CryptonightR_instruction14) +PUBLIC FN_PREFIX(CryptonightR_instruction15) +PUBLIC FN_PREFIX(CryptonightR_instruction16) +PUBLIC FN_PREFIX(CryptonightR_instruction17) +PUBLIC FN_PREFIX(CryptonightR_instruction18) +PUBLIC FN_PREFIX(CryptonightR_instruction19) +PUBLIC FN_PREFIX(CryptonightR_instruction20) +PUBLIC FN_PREFIX(CryptonightR_instruction21) +PUBLIC FN_PREFIX(CryptonightR_instruction22) +PUBLIC FN_PREFIX(CryptonightR_instruction23) +PUBLIC FN_PREFIX(CryptonightR_instruction24) +PUBLIC FN_PREFIX(CryptonightR_instruction25) +PUBLIC FN_PREFIX(CryptonightR_instruction26) +PUBLIC FN_PREFIX(CryptonightR_instruction27) +PUBLIC FN_PREFIX(CryptonightR_instruction28) +PUBLIC FN_PREFIX(CryptonightR_instruction29) +PUBLIC FN_PREFIX(CryptonightR_instruction30) +PUBLIC FN_PREFIX(CryptonightR_instruction31) +PUBLIC FN_PREFIX(CryptonightR_instruction32) +PUBLIC FN_PREFIX(CryptonightR_instruction33) +PUBLIC FN_PREFIX(CryptonightR_instruction34) +PUBLIC FN_PREFIX(CryptonightR_instruction35) +PUBLIC FN_PREFIX(CryptonightR_instruction36) +PUBLIC FN_PREFIX(CryptonightR_instruction37) +PUBLIC FN_PREFIX(CryptonightR_instruction38) +PUBLIC FN_PREFIX(CryptonightR_instruction39) +PUBLIC FN_PREFIX(CryptonightR_instruction40) +PUBLIC FN_PREFIX(CryptonightR_instruction41) +PUBLIC FN_PREFIX(CryptonightR_instruction42) +PUBLIC FN_PREFIX(CryptonightR_instruction43) +PUBLIC FN_PREFIX(CryptonightR_instruction44) +PUBLIC FN_PREFIX(CryptonightR_instruction45) +PUBLIC FN_PREFIX(CryptonightR_instruction46) +PUBLIC FN_PREFIX(CryptonightR_instruction47) +PUBLIC FN_PREFIX(CryptonightR_instruction48) +PUBLIC FN_PREFIX(CryptonightR_instruction49) +PUBLIC FN_PREFIX(CryptonightR_instruction50) +PUBLIC FN_PREFIX(CryptonightR_instruction51) +PUBLIC FN_PREFIX(CryptonightR_instruction52) +PUBLIC FN_PREFIX(CryptonightR_instruction53) +PUBLIC FN_PREFIX(CryptonightR_instruction54) +PUBLIC FN_PREFIX(CryptonightR_instruction55) +PUBLIC FN_PREFIX(CryptonightR_instruction56) +PUBLIC FN_PREFIX(CryptonightR_instruction57) +PUBLIC FN_PREFIX(CryptonightR_instruction58) +PUBLIC FN_PREFIX(CryptonightR_instruction59) +PUBLIC FN_PREFIX(CryptonightR_instruction60) +PUBLIC FN_PREFIX(CryptonightR_instruction61) +PUBLIC FN_PREFIX(CryptonightR_instruction62) +PUBLIC FN_PREFIX(CryptonightR_instruction63) +PUBLIC FN_PREFIX(CryptonightR_instruction64) +PUBLIC FN_PREFIX(CryptonightR_instruction65) +PUBLIC FN_PREFIX(CryptonightR_instruction66) +PUBLIC FN_PREFIX(CryptonightR_instruction67) +PUBLIC FN_PREFIX(CryptonightR_instruction68) +PUBLIC FN_PREFIX(CryptonightR_instruction69) +PUBLIC FN_PREFIX(CryptonightR_instruction70) +PUBLIC FN_PREFIX(CryptonightR_instruction71) +PUBLIC FN_PREFIX(CryptonightR_instruction72) +PUBLIC FN_PREFIX(CryptonightR_instruction73) +PUBLIC FN_PREFIX(CryptonightR_instruction74) +PUBLIC FN_PREFIX(CryptonightR_instruction75) +PUBLIC FN_PREFIX(CryptonightR_instruction76) +PUBLIC FN_PREFIX(CryptonightR_instruction77) +PUBLIC FN_PREFIX(CryptonightR_instruction78) +PUBLIC FN_PREFIX(CryptonightR_instruction79) +PUBLIC FN_PREFIX(CryptonightR_instruction80) +PUBLIC FN_PREFIX(CryptonightR_instruction81) +PUBLIC FN_PREFIX(CryptonightR_instruction82) +PUBLIC FN_PREFIX(CryptonightR_instruction83) +PUBLIC FN_PREFIX(CryptonightR_instruction84) +PUBLIC FN_PREFIX(CryptonightR_instruction85) +PUBLIC FN_PREFIX(CryptonightR_instruction86) +PUBLIC FN_PREFIX(CryptonightR_instruction87) +PUBLIC FN_PREFIX(CryptonightR_instruction88) +PUBLIC FN_PREFIX(CryptonightR_instruction89) +PUBLIC FN_PREFIX(CryptonightR_instruction90) +PUBLIC FN_PREFIX(CryptonightR_instruction91) +PUBLIC FN_PREFIX(CryptonightR_instruction92) +PUBLIC FN_PREFIX(CryptonightR_instruction93) +PUBLIC FN_PREFIX(CryptonightR_instruction94) +PUBLIC FN_PREFIX(CryptonightR_instruction95) +PUBLIC FN_PREFIX(CryptonightR_instruction96) +PUBLIC FN_PREFIX(CryptonightR_instruction97) +PUBLIC FN_PREFIX(CryptonightR_instruction98) +PUBLIC FN_PREFIX(CryptonightR_instruction99) +PUBLIC FN_PREFIX(CryptonightR_instruction100) +PUBLIC FN_PREFIX(CryptonightR_instruction101) +PUBLIC FN_PREFIX(CryptonightR_instruction102) +PUBLIC FN_PREFIX(CryptonightR_instruction103) +PUBLIC FN_PREFIX(CryptonightR_instruction104) +PUBLIC FN_PREFIX(CryptonightR_instruction105) +PUBLIC FN_PREFIX(CryptonightR_instruction106) +PUBLIC FN_PREFIX(CryptonightR_instruction107) +PUBLIC FN_PREFIX(CryptonightR_instruction108) +PUBLIC FN_PREFIX(CryptonightR_instruction109) +PUBLIC FN_PREFIX(CryptonightR_instruction110) +PUBLIC FN_PREFIX(CryptonightR_instruction111) +PUBLIC FN_PREFIX(CryptonightR_instruction112) +PUBLIC FN_PREFIX(CryptonightR_instruction113) +PUBLIC FN_PREFIX(CryptonightR_instruction114) +PUBLIC FN_PREFIX(CryptonightR_instruction115) +PUBLIC FN_PREFIX(CryptonightR_instruction116) +PUBLIC FN_PREFIX(CryptonightR_instruction117) +PUBLIC FN_PREFIX(CryptonightR_instruction118) +PUBLIC FN_PREFIX(CryptonightR_instruction119) +PUBLIC FN_PREFIX(CryptonightR_instruction120) +PUBLIC FN_PREFIX(CryptonightR_instruction121) +PUBLIC FN_PREFIX(CryptonightR_instruction122) +PUBLIC FN_PREFIX(CryptonightR_instruction123) +PUBLIC FN_PREFIX(CryptonightR_instruction124) +PUBLIC FN_PREFIX(CryptonightR_instruction125) +PUBLIC FN_PREFIX(CryptonightR_instruction126) +PUBLIC FN_PREFIX(CryptonightR_instruction127) +PUBLIC FN_PREFIX(CryptonightR_instruction128) +PUBLIC FN_PREFIX(CryptonightR_instruction129) +PUBLIC FN_PREFIX(CryptonightR_instruction130) +PUBLIC FN_PREFIX(CryptonightR_instruction131) +PUBLIC FN_PREFIX(CryptonightR_instruction132) +PUBLIC FN_PREFIX(CryptonightR_instruction133) +PUBLIC FN_PREFIX(CryptonightR_instruction134) +PUBLIC FN_PREFIX(CryptonightR_instruction135) +PUBLIC FN_PREFIX(CryptonightR_instruction136) +PUBLIC FN_PREFIX(CryptonightR_instruction137) +PUBLIC FN_PREFIX(CryptonightR_instruction138) +PUBLIC FN_PREFIX(CryptonightR_instruction139) +PUBLIC FN_PREFIX(CryptonightR_instruction140) +PUBLIC FN_PREFIX(CryptonightR_instruction141) +PUBLIC FN_PREFIX(CryptonightR_instruction142) +PUBLIC FN_PREFIX(CryptonightR_instruction143) +PUBLIC FN_PREFIX(CryptonightR_instruction144) +PUBLIC FN_PREFIX(CryptonightR_instruction145) +PUBLIC FN_PREFIX(CryptonightR_instruction146) +PUBLIC FN_PREFIX(CryptonightR_instruction147) +PUBLIC FN_PREFIX(CryptonightR_instruction148) +PUBLIC FN_PREFIX(CryptonightR_instruction149) +PUBLIC FN_PREFIX(CryptonightR_instruction150) +PUBLIC FN_PREFIX(CryptonightR_instruction151) +PUBLIC FN_PREFIX(CryptonightR_instruction152) +PUBLIC FN_PREFIX(CryptonightR_instruction153) +PUBLIC FN_PREFIX(CryptonightR_instruction154) +PUBLIC FN_PREFIX(CryptonightR_instruction155) +PUBLIC FN_PREFIX(CryptonightR_instruction156) +PUBLIC FN_PREFIX(CryptonightR_instruction157) +PUBLIC FN_PREFIX(CryptonightR_instruction158) +PUBLIC FN_PREFIX(CryptonightR_instruction159) +PUBLIC FN_PREFIX(CryptonightR_instruction160) +PUBLIC FN_PREFIX(CryptonightR_instruction161) +PUBLIC FN_PREFIX(CryptonightR_instruction162) +PUBLIC FN_PREFIX(CryptonightR_instruction163) +PUBLIC FN_PREFIX(CryptonightR_instruction164) +PUBLIC FN_PREFIX(CryptonightR_instruction165) +PUBLIC FN_PREFIX(CryptonightR_instruction166) +PUBLIC FN_PREFIX(CryptonightR_instruction167) +PUBLIC FN_PREFIX(CryptonightR_instruction168) +PUBLIC FN_PREFIX(CryptonightR_instruction169) +PUBLIC FN_PREFIX(CryptonightR_instruction170) +PUBLIC FN_PREFIX(CryptonightR_instruction171) +PUBLIC FN_PREFIX(CryptonightR_instruction172) +PUBLIC FN_PREFIX(CryptonightR_instruction173) +PUBLIC FN_PREFIX(CryptonightR_instruction174) +PUBLIC FN_PREFIX(CryptonightR_instruction175) +PUBLIC FN_PREFIX(CryptonightR_instruction176) +PUBLIC FN_PREFIX(CryptonightR_instruction177) +PUBLIC FN_PREFIX(CryptonightR_instruction178) +PUBLIC FN_PREFIX(CryptonightR_instruction179) +PUBLIC FN_PREFIX(CryptonightR_instruction180) +PUBLIC FN_PREFIX(CryptonightR_instruction181) +PUBLIC FN_PREFIX(CryptonightR_instruction182) +PUBLIC FN_PREFIX(CryptonightR_instruction183) +PUBLIC FN_PREFIX(CryptonightR_instruction184) +PUBLIC FN_PREFIX(CryptonightR_instruction185) +PUBLIC FN_PREFIX(CryptonightR_instruction186) +PUBLIC FN_PREFIX(CryptonightR_instruction187) +PUBLIC FN_PREFIX(CryptonightR_instruction188) +PUBLIC FN_PREFIX(CryptonightR_instruction189) +PUBLIC FN_PREFIX(CryptonightR_instruction190) +PUBLIC FN_PREFIX(CryptonightR_instruction191) +PUBLIC FN_PREFIX(CryptonightR_instruction192) +PUBLIC FN_PREFIX(CryptonightR_instruction193) +PUBLIC FN_PREFIX(CryptonightR_instruction194) +PUBLIC FN_PREFIX(CryptonightR_instruction195) +PUBLIC FN_PREFIX(CryptonightR_instruction196) +PUBLIC FN_PREFIX(CryptonightR_instruction197) +PUBLIC FN_PREFIX(CryptonightR_instruction198) +PUBLIC FN_PREFIX(CryptonightR_instruction199) +PUBLIC FN_PREFIX(CryptonightR_instruction200) +PUBLIC FN_PREFIX(CryptonightR_instruction201) +PUBLIC FN_PREFIX(CryptonightR_instruction202) +PUBLIC FN_PREFIX(CryptonightR_instruction203) +PUBLIC FN_PREFIX(CryptonightR_instruction204) +PUBLIC FN_PREFIX(CryptonightR_instruction205) +PUBLIC FN_PREFIX(CryptonightR_instruction206) +PUBLIC FN_PREFIX(CryptonightR_instruction207) +PUBLIC FN_PREFIX(CryptonightR_instruction208) +PUBLIC FN_PREFIX(CryptonightR_instruction209) +PUBLIC FN_PREFIX(CryptonightR_instruction210) +PUBLIC FN_PREFIX(CryptonightR_instruction211) +PUBLIC FN_PREFIX(CryptonightR_instruction212) +PUBLIC FN_PREFIX(CryptonightR_instruction213) +PUBLIC FN_PREFIX(CryptonightR_instruction214) +PUBLIC FN_PREFIX(CryptonightR_instruction215) +PUBLIC FN_PREFIX(CryptonightR_instruction216) +PUBLIC FN_PREFIX(CryptonightR_instruction217) +PUBLIC FN_PREFIX(CryptonightR_instruction218) +PUBLIC FN_PREFIX(CryptonightR_instruction219) +PUBLIC FN_PREFIX(CryptonightR_instruction220) +PUBLIC FN_PREFIX(CryptonightR_instruction221) +PUBLIC FN_PREFIX(CryptonightR_instruction222) +PUBLIC FN_PREFIX(CryptonightR_instruction223) +PUBLIC FN_PREFIX(CryptonightR_instruction224) +PUBLIC FN_PREFIX(CryptonightR_instruction225) +PUBLIC FN_PREFIX(CryptonightR_instruction226) +PUBLIC FN_PREFIX(CryptonightR_instruction227) +PUBLIC FN_PREFIX(CryptonightR_instruction228) +PUBLIC FN_PREFIX(CryptonightR_instruction229) +PUBLIC FN_PREFIX(CryptonightR_instruction230) +PUBLIC FN_PREFIX(CryptonightR_instruction231) +PUBLIC FN_PREFIX(CryptonightR_instruction232) +PUBLIC FN_PREFIX(CryptonightR_instruction233) +PUBLIC FN_PREFIX(CryptonightR_instruction234) +PUBLIC FN_PREFIX(CryptonightR_instruction235) +PUBLIC FN_PREFIX(CryptonightR_instruction236) +PUBLIC FN_PREFIX(CryptonightR_instruction237) +PUBLIC FN_PREFIX(CryptonightR_instruction238) +PUBLIC FN_PREFIX(CryptonightR_instruction239) +PUBLIC FN_PREFIX(CryptonightR_instruction240) +PUBLIC FN_PREFIX(CryptonightR_instruction241) +PUBLIC FN_PREFIX(CryptonightR_instruction242) +PUBLIC FN_PREFIX(CryptonightR_instruction243) +PUBLIC FN_PREFIX(CryptonightR_instruction244) +PUBLIC FN_PREFIX(CryptonightR_instruction245) +PUBLIC FN_PREFIX(CryptonightR_instruction246) +PUBLIC FN_PREFIX(CryptonightR_instruction247) +PUBLIC FN_PREFIX(CryptonightR_instruction248) +PUBLIC FN_PREFIX(CryptonightR_instruction249) +PUBLIC FN_PREFIX(CryptonightR_instruction250) +PUBLIC FN_PREFIX(CryptonightR_instruction251) +PUBLIC FN_PREFIX(CryptonightR_instruction252) +PUBLIC FN_PREFIX(CryptonightR_instruction253) +PUBLIC FN_PREFIX(CryptonightR_instruction254) +PUBLIC FN_PREFIX(CryptonightR_instruction255) +PUBLIC FN_PREFIX(CryptonightR_instruction256) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov0) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov1) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov2) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov3) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov4) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov5) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov6) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov7) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov8) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov9) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov10) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov11) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov12) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov13) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov14) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov15) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov16) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov17) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov18) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov19) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov20) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov21) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov22) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov23) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov24) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov25) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov26) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov27) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov28) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov29) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov30) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov31) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov32) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov33) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov34) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov35) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov36) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov37) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov38) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov39) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov40) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov41) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov42) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov43) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov44) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov45) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov46) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov47) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov48) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov49) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov50) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov51) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov52) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov53) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov54) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov55) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov56) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov57) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov58) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov59) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov60) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov61) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov62) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov63) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov64) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov65) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov66) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov67) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov68) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov69) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov70) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov71) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov72) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov73) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov74) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov75) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov76) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov77) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov78) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov79) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov80) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov81) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov82) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov83) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov84) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov85) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov86) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov87) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov88) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov89) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov90) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov91) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov92) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov93) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov94) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov95) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov96) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov97) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov98) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov99) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov100) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov101) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov102) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov103) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov104) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov105) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov106) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov107) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov108) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov109) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov110) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov111) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov112) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov113) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov114) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov115) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov116) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov117) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov118) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov119) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov120) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov121) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov122) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov123) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov124) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov125) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov126) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov127) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov128) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov129) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov130) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov131) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov132) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov133) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov134) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov135) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov136) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov137) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov138) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov139) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov140) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov141) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov142) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov143) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov144) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov145) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov146) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov147) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov148) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov149) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov150) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov151) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov152) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov153) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov154) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov155) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov156) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov157) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov158) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov159) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov160) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov161) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov162) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov163) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov164) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov165) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov166) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov167) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov168) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov169) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov170) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov171) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov172) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov173) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov174) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov175) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov176) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov177) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov178) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov179) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov180) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov181) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov182) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov183) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov184) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov185) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov186) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov187) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov188) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov189) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov190) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov191) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov192) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov193) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov194) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov195) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov196) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov197) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov198) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov199) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov200) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov201) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov202) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov203) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov204) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov205) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov206) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov207) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov208) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov209) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov210) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov211) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov212) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov213) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov214) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov215) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov216) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov217) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov218) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov219) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov220) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov221) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov222) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov223) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov224) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov225) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov226) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov227) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov228) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov229) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov230) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov231) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov232) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov233) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov234) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov235) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov236) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov237) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov238) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov239) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov240) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov241) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov242) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov243) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov244) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov245) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov246) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov247) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov248) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov249) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov250) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov251) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov252) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov253) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov254) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov255) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov256) + +#include "CryptonightWOW_template.inc" +#include "CryptonightR_template.inc" + +FN_PREFIX(CryptonightR_instruction0): + imul rbx, rbx +FN_PREFIX(CryptonightR_instruction1): + imul rbx, rbx +FN_PREFIX(CryptonightR_instruction2): + imul rbx, rbx +FN_PREFIX(CryptonightR_instruction3): + add rbx, r9 + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction4): + sub rbx, r9 +FN_PREFIX(CryptonightR_instruction5): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction6): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction7): + xor rbx, r9 +FN_PREFIX(CryptonightR_instruction8): + imul rsi, rbx +FN_PREFIX(CryptonightR_instruction9): + imul rsi, rbx +FN_PREFIX(CryptonightR_instruction10): + imul rsi, rbx +FN_PREFIX(CryptonightR_instruction11): + add rsi, rbx + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction12): + sub rsi, rbx +FN_PREFIX(CryptonightR_instruction13): + ror esi, cl +FN_PREFIX(CryptonightR_instruction14): + rol esi, cl +FN_PREFIX(CryptonightR_instruction15): + xor rsi, rbx +FN_PREFIX(CryptonightR_instruction16): + imul rdi, rbx +FN_PREFIX(CryptonightR_instruction17): + imul rdi, rbx +FN_PREFIX(CryptonightR_instruction18): + imul rdi, rbx +FN_PREFIX(CryptonightR_instruction19): + add rdi, rbx + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction20): + sub rdi, rbx +FN_PREFIX(CryptonightR_instruction21): + ror edi, cl +FN_PREFIX(CryptonightR_instruction22): + rol edi, cl +FN_PREFIX(CryptonightR_instruction23): + xor rdi, rbx +FN_PREFIX(CryptonightR_instruction24): + imul rbp, rbx +FN_PREFIX(CryptonightR_instruction25): + imul rbp, rbx +FN_PREFIX(CryptonightR_instruction26): + imul rbp, rbx +FN_PREFIX(CryptonightR_instruction27): + add rbp, rbx + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction28): + sub rbp, rbx +FN_PREFIX(CryptonightR_instruction29): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction30): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction31): + xor rbp, rbx +FN_PREFIX(CryptonightR_instruction32): + imul rbx, rsi +FN_PREFIX(CryptonightR_instruction33): + imul rbx, rsi +FN_PREFIX(CryptonightR_instruction34): + imul rbx, rsi +FN_PREFIX(CryptonightR_instruction35): + add rbx, rsi + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction36): + sub rbx, rsi +FN_PREFIX(CryptonightR_instruction37): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction38): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction39): + xor rbx, rsi +FN_PREFIX(CryptonightR_instruction40): + imul rsi, rsi +FN_PREFIX(CryptonightR_instruction41): + imul rsi, rsi +FN_PREFIX(CryptonightR_instruction42): + imul rsi, rsi +FN_PREFIX(CryptonightR_instruction43): + add rsi, r9 + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction44): + sub rsi, r9 +FN_PREFIX(CryptonightR_instruction45): + ror esi, cl +FN_PREFIX(CryptonightR_instruction46): + rol esi, cl +FN_PREFIX(CryptonightR_instruction47): + xor rsi, r9 +FN_PREFIX(CryptonightR_instruction48): + imul rdi, rsi +FN_PREFIX(CryptonightR_instruction49): + imul rdi, rsi +FN_PREFIX(CryptonightR_instruction50): + imul rdi, rsi +FN_PREFIX(CryptonightR_instruction51): + add rdi, rsi + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction52): + sub rdi, rsi +FN_PREFIX(CryptonightR_instruction53): + ror edi, cl +FN_PREFIX(CryptonightR_instruction54): + rol edi, cl +FN_PREFIX(CryptonightR_instruction55): + xor rdi, rsi +FN_PREFIX(CryptonightR_instruction56): + imul rbp, rsi +FN_PREFIX(CryptonightR_instruction57): + imul rbp, rsi +FN_PREFIX(CryptonightR_instruction58): + imul rbp, rsi +FN_PREFIX(CryptonightR_instruction59): + add rbp, rsi + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction60): + sub rbp, rsi +FN_PREFIX(CryptonightR_instruction61): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction62): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction63): + xor rbp, rsi +FN_PREFIX(CryptonightR_instruction64): + imul rbx, rdi +FN_PREFIX(CryptonightR_instruction65): + imul rbx, rdi +FN_PREFIX(CryptonightR_instruction66): + imul rbx, rdi +FN_PREFIX(CryptonightR_instruction67): + add rbx, rdi + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction68): + sub rbx, rdi +FN_PREFIX(CryptonightR_instruction69): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction70): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction71): + xor rbx, rdi +FN_PREFIX(CryptonightR_instruction72): + imul rsi, rdi +FN_PREFIX(CryptonightR_instruction73): + imul rsi, rdi +FN_PREFIX(CryptonightR_instruction74): + imul rsi, rdi +FN_PREFIX(CryptonightR_instruction75): + add rsi, rdi + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction76): + sub rsi, rdi +FN_PREFIX(CryptonightR_instruction77): + ror esi, cl +FN_PREFIX(CryptonightR_instruction78): + rol esi, cl +FN_PREFIX(CryptonightR_instruction79): + xor rsi, rdi +FN_PREFIX(CryptonightR_instruction80): + imul rdi, rdi +FN_PREFIX(CryptonightR_instruction81): + imul rdi, rdi +FN_PREFIX(CryptonightR_instruction82): + imul rdi, rdi +FN_PREFIX(CryptonightR_instruction83): + add rdi, r9 + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction84): + sub rdi, r9 +FN_PREFIX(CryptonightR_instruction85): + ror edi, cl +FN_PREFIX(CryptonightR_instruction86): + rol edi, cl +FN_PREFIX(CryptonightR_instruction87): + xor rdi, r9 +FN_PREFIX(CryptonightR_instruction88): + imul rbp, rdi +FN_PREFIX(CryptonightR_instruction89): + imul rbp, rdi +FN_PREFIX(CryptonightR_instruction90): + imul rbp, rdi +FN_PREFIX(CryptonightR_instruction91): + add rbp, rdi + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction92): + sub rbp, rdi +FN_PREFIX(CryptonightR_instruction93): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction94): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction95): + xor rbp, rdi +FN_PREFIX(CryptonightR_instruction96): + imul rbx, rbp +FN_PREFIX(CryptonightR_instruction97): + imul rbx, rbp +FN_PREFIX(CryptonightR_instruction98): + imul rbx, rbp +FN_PREFIX(CryptonightR_instruction99): + add rbx, rbp + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction100): + sub rbx, rbp +FN_PREFIX(CryptonightR_instruction101): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction102): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction103): + xor rbx, rbp +FN_PREFIX(CryptonightR_instruction104): + imul rsi, rbp +FN_PREFIX(CryptonightR_instruction105): + imul rsi, rbp +FN_PREFIX(CryptonightR_instruction106): + imul rsi, rbp +FN_PREFIX(CryptonightR_instruction107): + add rsi, rbp + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction108): + sub rsi, rbp +FN_PREFIX(CryptonightR_instruction109): + ror esi, cl +FN_PREFIX(CryptonightR_instruction110): + rol esi, cl +FN_PREFIX(CryptonightR_instruction111): + xor rsi, rbp +FN_PREFIX(CryptonightR_instruction112): + imul rdi, rbp +FN_PREFIX(CryptonightR_instruction113): + imul rdi, rbp +FN_PREFIX(CryptonightR_instruction114): + imul rdi, rbp +FN_PREFIX(CryptonightR_instruction115): + add rdi, rbp + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction116): + sub rdi, rbp +FN_PREFIX(CryptonightR_instruction117): + ror edi, cl +FN_PREFIX(CryptonightR_instruction118): + rol edi, cl +FN_PREFIX(CryptonightR_instruction119): + xor rdi, rbp +FN_PREFIX(CryptonightR_instruction120): + imul rbp, rbp +FN_PREFIX(CryptonightR_instruction121): + imul rbp, rbp +FN_PREFIX(CryptonightR_instruction122): + imul rbp, rbp +FN_PREFIX(CryptonightR_instruction123): + add rbp, r9 + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction124): + sub rbp, r9 +FN_PREFIX(CryptonightR_instruction125): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction126): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction127): + xor rbp, r9 +FN_PREFIX(CryptonightR_instruction128): + imul rbx, rsp +FN_PREFIX(CryptonightR_instruction129): + imul rbx, rsp +FN_PREFIX(CryptonightR_instruction130): + imul rbx, rsp +FN_PREFIX(CryptonightR_instruction131): + add rbx, rsp + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction132): + sub rbx, rsp +FN_PREFIX(CryptonightR_instruction133): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction134): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction135): + xor rbx, rsp +FN_PREFIX(CryptonightR_instruction136): + imul rsi, rsp +FN_PREFIX(CryptonightR_instruction137): + imul rsi, rsp +FN_PREFIX(CryptonightR_instruction138): + imul rsi, rsp +FN_PREFIX(CryptonightR_instruction139): + add rsi, rsp + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction140): + sub rsi, rsp +FN_PREFIX(CryptonightR_instruction141): + ror esi, cl +FN_PREFIX(CryptonightR_instruction142): + rol esi, cl +FN_PREFIX(CryptonightR_instruction143): + xor rsi, rsp +FN_PREFIX(CryptonightR_instruction144): + imul rdi, rsp +FN_PREFIX(CryptonightR_instruction145): + imul rdi, rsp +FN_PREFIX(CryptonightR_instruction146): + imul rdi, rsp +FN_PREFIX(CryptonightR_instruction147): + add rdi, rsp + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction148): + sub rdi, rsp +FN_PREFIX(CryptonightR_instruction149): + ror edi, cl +FN_PREFIX(CryptonightR_instruction150): + rol edi, cl +FN_PREFIX(CryptonightR_instruction151): + xor rdi, rsp +FN_PREFIX(CryptonightR_instruction152): + imul rbp, rsp +FN_PREFIX(CryptonightR_instruction153): + imul rbp, rsp +FN_PREFIX(CryptonightR_instruction154): + imul rbp, rsp +FN_PREFIX(CryptonightR_instruction155): + add rbp, rsp + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction156): + sub rbp, rsp +FN_PREFIX(CryptonightR_instruction157): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction158): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction159): + xor rbp, rsp +FN_PREFIX(CryptonightR_instruction160): + imul rbx, r15 +FN_PREFIX(CryptonightR_instruction161): + imul rbx, r15 +FN_PREFIX(CryptonightR_instruction162): + imul rbx, r15 +FN_PREFIX(CryptonightR_instruction163): + add rbx, r15 + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction164): + sub rbx, r15 +FN_PREFIX(CryptonightR_instruction165): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction166): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction167): + xor rbx, r15 +FN_PREFIX(CryptonightR_instruction168): + imul rsi, r15 +FN_PREFIX(CryptonightR_instruction169): + imul rsi, r15 +FN_PREFIX(CryptonightR_instruction170): + imul rsi, r15 +FN_PREFIX(CryptonightR_instruction171): + add rsi, r15 + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction172): + sub rsi, r15 +FN_PREFIX(CryptonightR_instruction173): + ror esi, cl +FN_PREFIX(CryptonightR_instruction174): + rol esi, cl +FN_PREFIX(CryptonightR_instruction175): + xor rsi, r15 +FN_PREFIX(CryptonightR_instruction176): + imul rdi, r15 +FN_PREFIX(CryptonightR_instruction177): + imul rdi, r15 +FN_PREFIX(CryptonightR_instruction178): + imul rdi, r15 +FN_PREFIX(CryptonightR_instruction179): + add rdi, r15 + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction180): + sub rdi, r15 +FN_PREFIX(CryptonightR_instruction181): + ror edi, cl +FN_PREFIX(CryptonightR_instruction182): + rol edi, cl +FN_PREFIX(CryptonightR_instruction183): + xor rdi, r15 +FN_PREFIX(CryptonightR_instruction184): + imul rbp, r15 +FN_PREFIX(CryptonightR_instruction185): + imul rbp, r15 +FN_PREFIX(CryptonightR_instruction186): + imul rbp, r15 +FN_PREFIX(CryptonightR_instruction187): + add rbp, r15 + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction188): + sub rbp, r15 +FN_PREFIX(CryptonightR_instruction189): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction190): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction191): + xor rbp, r15 +FN_PREFIX(CryptonightR_instruction192): + imul rbx, rax +FN_PREFIX(CryptonightR_instruction193): + imul rbx, rax +FN_PREFIX(CryptonightR_instruction194): + imul rbx, rax +FN_PREFIX(CryptonightR_instruction195): + add rbx, rax + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction196): + sub rbx, rax +FN_PREFIX(CryptonightR_instruction197): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction198): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction199): + xor rbx, rax +FN_PREFIX(CryptonightR_instruction200): + imul rsi, rax +FN_PREFIX(CryptonightR_instruction201): + imul rsi, rax +FN_PREFIX(CryptonightR_instruction202): + imul rsi, rax +FN_PREFIX(CryptonightR_instruction203): + add rsi, rax + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction204): + sub rsi, rax +FN_PREFIX(CryptonightR_instruction205): + ror esi, cl +FN_PREFIX(CryptonightR_instruction206): + rol esi, cl +FN_PREFIX(CryptonightR_instruction207): + xor rsi, rax +FN_PREFIX(CryptonightR_instruction208): + imul rdi, rax +FN_PREFIX(CryptonightR_instruction209): + imul rdi, rax +FN_PREFIX(CryptonightR_instruction210): + imul rdi, rax +FN_PREFIX(CryptonightR_instruction211): + add rdi, rax + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction212): + sub rdi, rax +FN_PREFIX(CryptonightR_instruction213): + ror edi, cl +FN_PREFIX(CryptonightR_instruction214): + rol edi, cl +FN_PREFIX(CryptonightR_instruction215): + xor rdi, rax +FN_PREFIX(CryptonightR_instruction216): + imul rbp, rax +FN_PREFIX(CryptonightR_instruction217): + imul rbp, rax +FN_PREFIX(CryptonightR_instruction218): + imul rbp, rax +FN_PREFIX(CryptonightR_instruction219): + add rbp, rax + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction220): + sub rbp, rax +FN_PREFIX(CryptonightR_instruction221): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction222): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction223): + xor rbp, rax +FN_PREFIX(CryptonightR_instruction224): + imul rbx, rdx +FN_PREFIX(CryptonightR_instruction225): + imul rbx, rdx +FN_PREFIX(CryptonightR_instruction226): + imul rbx, rdx +FN_PREFIX(CryptonightR_instruction227): + add rbx, rdx + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction228): + sub rbx, rdx +FN_PREFIX(CryptonightR_instruction229): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction230): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction231): + xor rbx, rdx +FN_PREFIX(CryptonightR_instruction232): + imul rsi, rdx +FN_PREFIX(CryptonightR_instruction233): + imul rsi, rdx +FN_PREFIX(CryptonightR_instruction234): + imul rsi, rdx +FN_PREFIX(CryptonightR_instruction235): + add rsi, rdx + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction236): + sub rsi, rdx +FN_PREFIX(CryptonightR_instruction237): + ror esi, cl +FN_PREFIX(CryptonightR_instruction238): + rol esi, cl +FN_PREFIX(CryptonightR_instruction239): + xor rsi, rdx +FN_PREFIX(CryptonightR_instruction240): + imul rdi, rdx +FN_PREFIX(CryptonightR_instruction241): + imul rdi, rdx +FN_PREFIX(CryptonightR_instruction242): + imul rdi, rdx +FN_PREFIX(CryptonightR_instruction243): + add rdi, rdx + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction244): + sub rdi, rdx +FN_PREFIX(CryptonightR_instruction245): + ror edi, cl +FN_PREFIX(CryptonightR_instruction246): + rol edi, cl +FN_PREFIX(CryptonightR_instruction247): + xor rdi, rdx +FN_PREFIX(CryptonightR_instruction248): + imul rbp, rdx +FN_PREFIX(CryptonightR_instruction249): + imul rbp, rdx +FN_PREFIX(CryptonightR_instruction250): + imul rbp, rdx +FN_PREFIX(CryptonightR_instruction251): + add rbp, rdx + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction252): + sub rbp, rdx +FN_PREFIX(CryptonightR_instruction253): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction254): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction255): + xor rbp, rdx +FN_PREFIX(CryptonightR_instruction256): + imul rbx, rbx +FN_PREFIX(CryptonightR_instruction_mov0): + +FN_PREFIX(CryptonightR_instruction_mov1): + +FN_PREFIX(CryptonightR_instruction_mov2): + +FN_PREFIX(CryptonightR_instruction_mov3): + +FN_PREFIX(CryptonightR_instruction_mov4): + +FN_PREFIX(CryptonightR_instruction_mov5): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov6): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov7): + +FN_PREFIX(CryptonightR_instruction_mov8): + +FN_PREFIX(CryptonightR_instruction_mov9): + +FN_PREFIX(CryptonightR_instruction_mov10): + +FN_PREFIX(CryptonightR_instruction_mov11): + +FN_PREFIX(CryptonightR_instruction_mov12): + +FN_PREFIX(CryptonightR_instruction_mov13): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov14): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov15): + +FN_PREFIX(CryptonightR_instruction_mov16): + +FN_PREFIX(CryptonightR_instruction_mov17): + +FN_PREFIX(CryptonightR_instruction_mov18): + +FN_PREFIX(CryptonightR_instruction_mov19): + +FN_PREFIX(CryptonightR_instruction_mov20): + +FN_PREFIX(CryptonightR_instruction_mov21): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov22): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov23): + +FN_PREFIX(CryptonightR_instruction_mov24): + +FN_PREFIX(CryptonightR_instruction_mov25): + +FN_PREFIX(CryptonightR_instruction_mov26): + +FN_PREFIX(CryptonightR_instruction_mov27): + +FN_PREFIX(CryptonightR_instruction_mov28): + +FN_PREFIX(CryptonightR_instruction_mov29): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov30): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov31): + +FN_PREFIX(CryptonightR_instruction_mov32): + +FN_PREFIX(CryptonightR_instruction_mov33): + +FN_PREFIX(CryptonightR_instruction_mov34): + +FN_PREFIX(CryptonightR_instruction_mov35): + +FN_PREFIX(CryptonightR_instruction_mov36): + +FN_PREFIX(CryptonightR_instruction_mov37): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov38): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov39): + +FN_PREFIX(CryptonightR_instruction_mov40): + +FN_PREFIX(CryptonightR_instruction_mov41): + +FN_PREFIX(CryptonightR_instruction_mov42): + +FN_PREFIX(CryptonightR_instruction_mov43): + +FN_PREFIX(CryptonightR_instruction_mov44): + +FN_PREFIX(CryptonightR_instruction_mov45): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov46): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov47): + +FN_PREFIX(CryptonightR_instruction_mov48): + +FN_PREFIX(CryptonightR_instruction_mov49): + +FN_PREFIX(CryptonightR_instruction_mov50): + +FN_PREFIX(CryptonightR_instruction_mov51): + +FN_PREFIX(CryptonightR_instruction_mov52): + +FN_PREFIX(CryptonightR_instruction_mov53): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov54): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov55): + +FN_PREFIX(CryptonightR_instruction_mov56): + +FN_PREFIX(CryptonightR_instruction_mov57): + +FN_PREFIX(CryptonightR_instruction_mov58): + +FN_PREFIX(CryptonightR_instruction_mov59): + +FN_PREFIX(CryptonightR_instruction_mov60): + +FN_PREFIX(CryptonightR_instruction_mov61): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov62): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov63): + +FN_PREFIX(CryptonightR_instruction_mov64): + +FN_PREFIX(CryptonightR_instruction_mov65): + +FN_PREFIX(CryptonightR_instruction_mov66): + +FN_PREFIX(CryptonightR_instruction_mov67): + +FN_PREFIX(CryptonightR_instruction_mov68): + +FN_PREFIX(CryptonightR_instruction_mov69): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov70): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov71): + +FN_PREFIX(CryptonightR_instruction_mov72): + +FN_PREFIX(CryptonightR_instruction_mov73): + +FN_PREFIX(CryptonightR_instruction_mov74): + +FN_PREFIX(CryptonightR_instruction_mov75): + +FN_PREFIX(CryptonightR_instruction_mov76): + +FN_PREFIX(CryptonightR_instruction_mov77): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov78): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov79): + +FN_PREFIX(CryptonightR_instruction_mov80): + +FN_PREFIX(CryptonightR_instruction_mov81): + +FN_PREFIX(CryptonightR_instruction_mov82): + +FN_PREFIX(CryptonightR_instruction_mov83): + +FN_PREFIX(CryptonightR_instruction_mov84): + +FN_PREFIX(CryptonightR_instruction_mov85): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov86): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov87): + +FN_PREFIX(CryptonightR_instruction_mov88): + +FN_PREFIX(CryptonightR_instruction_mov89): + +FN_PREFIX(CryptonightR_instruction_mov90): + +FN_PREFIX(CryptonightR_instruction_mov91): + +FN_PREFIX(CryptonightR_instruction_mov92): + +FN_PREFIX(CryptonightR_instruction_mov93): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov94): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov95): + +FN_PREFIX(CryptonightR_instruction_mov96): + +FN_PREFIX(CryptonightR_instruction_mov97): + +FN_PREFIX(CryptonightR_instruction_mov98): + +FN_PREFIX(CryptonightR_instruction_mov99): + +FN_PREFIX(CryptonightR_instruction_mov100): + +FN_PREFIX(CryptonightR_instruction_mov101): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov102): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov103): + +FN_PREFIX(CryptonightR_instruction_mov104): + +FN_PREFIX(CryptonightR_instruction_mov105): + +FN_PREFIX(CryptonightR_instruction_mov106): + +FN_PREFIX(CryptonightR_instruction_mov107): + +FN_PREFIX(CryptonightR_instruction_mov108): + +FN_PREFIX(CryptonightR_instruction_mov109): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov110): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov111): + +FN_PREFIX(CryptonightR_instruction_mov112): + +FN_PREFIX(CryptonightR_instruction_mov113): + +FN_PREFIX(CryptonightR_instruction_mov114): + +FN_PREFIX(CryptonightR_instruction_mov115): + +FN_PREFIX(CryptonightR_instruction_mov116): + +FN_PREFIX(CryptonightR_instruction_mov117): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov118): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov119): + +FN_PREFIX(CryptonightR_instruction_mov120): + +FN_PREFIX(CryptonightR_instruction_mov121): + +FN_PREFIX(CryptonightR_instruction_mov122): + +FN_PREFIX(CryptonightR_instruction_mov123): + +FN_PREFIX(CryptonightR_instruction_mov124): + +FN_PREFIX(CryptonightR_instruction_mov125): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov126): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov127): + +FN_PREFIX(CryptonightR_instruction_mov128): + +FN_PREFIX(CryptonightR_instruction_mov129): + +FN_PREFIX(CryptonightR_instruction_mov130): + +FN_PREFIX(CryptonightR_instruction_mov131): + +FN_PREFIX(CryptonightR_instruction_mov132): + +FN_PREFIX(CryptonightR_instruction_mov133): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov134): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov135): + +FN_PREFIX(CryptonightR_instruction_mov136): + +FN_PREFIX(CryptonightR_instruction_mov137): + +FN_PREFIX(CryptonightR_instruction_mov138): + +FN_PREFIX(CryptonightR_instruction_mov139): + +FN_PREFIX(CryptonightR_instruction_mov140): + +FN_PREFIX(CryptonightR_instruction_mov141): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov142): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov143): + +FN_PREFIX(CryptonightR_instruction_mov144): + +FN_PREFIX(CryptonightR_instruction_mov145): + +FN_PREFIX(CryptonightR_instruction_mov146): + +FN_PREFIX(CryptonightR_instruction_mov147): + +FN_PREFIX(CryptonightR_instruction_mov148): + +FN_PREFIX(CryptonightR_instruction_mov149): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov150): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov151): + +FN_PREFIX(CryptonightR_instruction_mov152): + +FN_PREFIX(CryptonightR_instruction_mov153): + +FN_PREFIX(CryptonightR_instruction_mov154): + +FN_PREFIX(CryptonightR_instruction_mov155): + +FN_PREFIX(CryptonightR_instruction_mov156): + +FN_PREFIX(CryptonightR_instruction_mov157): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov158): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov159): + +FN_PREFIX(CryptonightR_instruction_mov160): + +FN_PREFIX(CryptonightR_instruction_mov161): + +FN_PREFIX(CryptonightR_instruction_mov162): + +FN_PREFIX(CryptonightR_instruction_mov163): + +FN_PREFIX(CryptonightR_instruction_mov164): + +FN_PREFIX(CryptonightR_instruction_mov165): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov166): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov167): + +FN_PREFIX(CryptonightR_instruction_mov168): + +FN_PREFIX(CryptonightR_instruction_mov169): + +FN_PREFIX(CryptonightR_instruction_mov170): + +FN_PREFIX(CryptonightR_instruction_mov171): + +FN_PREFIX(CryptonightR_instruction_mov172): + +FN_PREFIX(CryptonightR_instruction_mov173): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov174): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov175): + +FN_PREFIX(CryptonightR_instruction_mov176): + +FN_PREFIX(CryptonightR_instruction_mov177): + +FN_PREFIX(CryptonightR_instruction_mov178): + +FN_PREFIX(CryptonightR_instruction_mov179): + +FN_PREFIX(CryptonightR_instruction_mov180): + +FN_PREFIX(CryptonightR_instruction_mov181): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov182): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov183): + +FN_PREFIX(CryptonightR_instruction_mov184): + +FN_PREFIX(CryptonightR_instruction_mov185): + +FN_PREFIX(CryptonightR_instruction_mov186): + +FN_PREFIX(CryptonightR_instruction_mov187): + +FN_PREFIX(CryptonightR_instruction_mov188): + +FN_PREFIX(CryptonightR_instruction_mov189): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov190): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov191): + +FN_PREFIX(CryptonightR_instruction_mov192): + +FN_PREFIX(CryptonightR_instruction_mov193): + +FN_PREFIX(CryptonightR_instruction_mov194): + +FN_PREFIX(CryptonightR_instruction_mov195): + +FN_PREFIX(CryptonightR_instruction_mov196): + +FN_PREFIX(CryptonightR_instruction_mov197): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov198): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov199): + +FN_PREFIX(CryptonightR_instruction_mov200): + +FN_PREFIX(CryptonightR_instruction_mov201): + +FN_PREFIX(CryptonightR_instruction_mov202): + +FN_PREFIX(CryptonightR_instruction_mov203): + +FN_PREFIX(CryptonightR_instruction_mov204): + +FN_PREFIX(CryptonightR_instruction_mov205): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov206): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov207): + +FN_PREFIX(CryptonightR_instruction_mov208): + +FN_PREFIX(CryptonightR_instruction_mov209): + +FN_PREFIX(CryptonightR_instruction_mov210): + +FN_PREFIX(CryptonightR_instruction_mov211): + +FN_PREFIX(CryptonightR_instruction_mov212): + +FN_PREFIX(CryptonightR_instruction_mov213): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov214): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov215): + +FN_PREFIX(CryptonightR_instruction_mov216): + +FN_PREFIX(CryptonightR_instruction_mov217): + +FN_PREFIX(CryptonightR_instruction_mov218): + +FN_PREFIX(CryptonightR_instruction_mov219): + +FN_PREFIX(CryptonightR_instruction_mov220): + +FN_PREFIX(CryptonightR_instruction_mov221): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov222): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov223): + +FN_PREFIX(CryptonightR_instruction_mov224): + +FN_PREFIX(CryptonightR_instruction_mov225): + +FN_PREFIX(CryptonightR_instruction_mov226): + +FN_PREFIX(CryptonightR_instruction_mov227): + +FN_PREFIX(CryptonightR_instruction_mov228): + +FN_PREFIX(CryptonightR_instruction_mov229): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov230): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov231): + +FN_PREFIX(CryptonightR_instruction_mov232): + +FN_PREFIX(CryptonightR_instruction_mov233): + +FN_PREFIX(CryptonightR_instruction_mov234): + +FN_PREFIX(CryptonightR_instruction_mov235): + +FN_PREFIX(CryptonightR_instruction_mov236): + +FN_PREFIX(CryptonightR_instruction_mov237): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov238): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov239): + +FN_PREFIX(CryptonightR_instruction_mov240): + +FN_PREFIX(CryptonightR_instruction_mov241): + +FN_PREFIX(CryptonightR_instruction_mov242): + +FN_PREFIX(CryptonightR_instruction_mov243): + +FN_PREFIX(CryptonightR_instruction_mov244): + +FN_PREFIX(CryptonightR_instruction_mov245): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov246): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov247): + +FN_PREFIX(CryptonightR_instruction_mov248): + +FN_PREFIX(CryptonightR_instruction_mov249): + +FN_PREFIX(CryptonightR_instruction_mov250): + +FN_PREFIX(CryptonightR_instruction_mov251): + +FN_PREFIX(CryptonightR_instruction_mov252): + +FN_PREFIX(CryptonightR_instruction_mov253): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov254): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov255): + +FN_PREFIX(CryptonightR_instruction_mov256): diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.h b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.h new file mode 100644 index 000000000..c2054705b --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.h @@ -0,0 +1,1063 @@ +// Auto-generated file, do not edit + +extern "C" +{ + void CryptonightWOW_template_part1(); + void CryptonightWOW_template_mainloop(); + void CryptonightWOW_template_part2(); + void CryptonightWOW_template_part3(); + void CryptonightWOW_template_end(); + void CryptonightWOW_template_double_part1(); + void CryptonightWOW_template_double_mainloop(); + void CryptonightWOW_template_double_part2(); + void CryptonightWOW_template_double_part3(); + void CryptonightWOW_template_double_part4(); + void CryptonightWOW_template_double_end(); + + void CryptonightR_template_part1(); + void CryptonightR_template_mainloop(); + void CryptonightR_template_part2(); + void CryptonightR_template_part3(); + void CryptonightR_template_end(); + void CryptonightR_template_double_part1(); + void CryptonightR_template_double_mainloop(); + void CryptonightR_template_double_part2(); + void CryptonightR_template_double_part3(); + void CryptonightR_template_double_part4(); + void CryptonightR_template_double_end(); + + void CryptonightR_instruction0(); + void CryptonightR_instruction1(); + void CryptonightR_instruction2(); + void CryptonightR_instruction3(); + void CryptonightR_instruction4(); + void CryptonightR_instruction5(); + void CryptonightR_instruction6(); + void CryptonightR_instruction7(); + void CryptonightR_instruction8(); + void CryptonightR_instruction9(); + void CryptonightR_instruction10(); + void CryptonightR_instruction11(); + void CryptonightR_instruction12(); + void CryptonightR_instruction13(); + void CryptonightR_instruction14(); + void CryptonightR_instruction15(); + void CryptonightR_instruction16(); + void CryptonightR_instruction17(); + void CryptonightR_instruction18(); + void CryptonightR_instruction19(); + void CryptonightR_instruction20(); + void CryptonightR_instruction21(); + void CryptonightR_instruction22(); + void CryptonightR_instruction23(); + void CryptonightR_instruction24(); + void CryptonightR_instruction25(); + void CryptonightR_instruction26(); + void CryptonightR_instruction27(); + void CryptonightR_instruction28(); + void CryptonightR_instruction29(); + void CryptonightR_instruction30(); + void CryptonightR_instruction31(); + void CryptonightR_instruction32(); + void CryptonightR_instruction33(); + void CryptonightR_instruction34(); + void CryptonightR_instruction35(); + void CryptonightR_instruction36(); + void CryptonightR_instruction37(); + void CryptonightR_instruction38(); + void CryptonightR_instruction39(); + void CryptonightR_instruction40(); + void CryptonightR_instruction41(); + void CryptonightR_instruction42(); + void CryptonightR_instruction43(); + void CryptonightR_instruction44(); + void CryptonightR_instruction45(); + void CryptonightR_instruction46(); + void CryptonightR_instruction47(); + void CryptonightR_instruction48(); + void CryptonightR_instruction49(); + void CryptonightR_instruction50(); + void CryptonightR_instruction51(); + void CryptonightR_instruction52(); + void CryptonightR_instruction53(); + void CryptonightR_instruction54(); + void CryptonightR_instruction55(); + void CryptonightR_instruction56(); + void CryptonightR_instruction57(); + void CryptonightR_instruction58(); + void CryptonightR_instruction59(); + void CryptonightR_instruction60(); + void CryptonightR_instruction61(); + void CryptonightR_instruction62(); + void CryptonightR_instruction63(); + void CryptonightR_instruction64(); + void CryptonightR_instruction65(); + void CryptonightR_instruction66(); + void CryptonightR_instruction67(); + void CryptonightR_instruction68(); + void CryptonightR_instruction69(); + void CryptonightR_instruction70(); + void CryptonightR_instruction71(); + void CryptonightR_instruction72(); + void CryptonightR_instruction73(); + void CryptonightR_instruction74(); + void CryptonightR_instruction75(); + void CryptonightR_instruction76(); + void CryptonightR_instruction77(); + void CryptonightR_instruction78(); + void CryptonightR_instruction79(); + void CryptonightR_instruction80(); + void CryptonightR_instruction81(); + void CryptonightR_instruction82(); + void CryptonightR_instruction83(); + void CryptonightR_instruction84(); + void CryptonightR_instruction85(); + void CryptonightR_instruction86(); + void CryptonightR_instruction87(); + void CryptonightR_instruction88(); + void CryptonightR_instruction89(); + void CryptonightR_instruction90(); + void CryptonightR_instruction91(); + void CryptonightR_instruction92(); + void CryptonightR_instruction93(); + void CryptonightR_instruction94(); + void CryptonightR_instruction95(); + void CryptonightR_instruction96(); + void CryptonightR_instruction97(); + void CryptonightR_instruction98(); + void CryptonightR_instruction99(); + void CryptonightR_instruction100(); + void CryptonightR_instruction101(); + void CryptonightR_instruction102(); + void CryptonightR_instruction103(); + void CryptonightR_instruction104(); + void CryptonightR_instruction105(); + void CryptonightR_instruction106(); + void CryptonightR_instruction107(); + void CryptonightR_instruction108(); + void CryptonightR_instruction109(); + void CryptonightR_instruction110(); + void CryptonightR_instruction111(); + void CryptonightR_instruction112(); + void CryptonightR_instruction113(); + void CryptonightR_instruction114(); + void CryptonightR_instruction115(); + void CryptonightR_instruction116(); + void CryptonightR_instruction117(); + void CryptonightR_instruction118(); + void CryptonightR_instruction119(); + void CryptonightR_instruction120(); + void CryptonightR_instruction121(); + void CryptonightR_instruction122(); + void CryptonightR_instruction123(); + void CryptonightR_instruction124(); + void CryptonightR_instruction125(); + void CryptonightR_instruction126(); + void CryptonightR_instruction127(); + void CryptonightR_instruction128(); + void CryptonightR_instruction129(); + void CryptonightR_instruction130(); + void CryptonightR_instruction131(); + void CryptonightR_instruction132(); + void CryptonightR_instruction133(); + void CryptonightR_instruction134(); + void CryptonightR_instruction135(); + void CryptonightR_instruction136(); + void CryptonightR_instruction137(); + void CryptonightR_instruction138(); + void CryptonightR_instruction139(); + void CryptonightR_instruction140(); + void CryptonightR_instruction141(); + void CryptonightR_instruction142(); + void CryptonightR_instruction143(); + void CryptonightR_instruction144(); + void CryptonightR_instruction145(); + void CryptonightR_instruction146(); + void CryptonightR_instruction147(); + void CryptonightR_instruction148(); + void CryptonightR_instruction149(); + void CryptonightR_instruction150(); + void CryptonightR_instruction151(); + void CryptonightR_instruction152(); + void CryptonightR_instruction153(); + void CryptonightR_instruction154(); + void CryptonightR_instruction155(); + void CryptonightR_instruction156(); + void CryptonightR_instruction157(); + void CryptonightR_instruction158(); + void CryptonightR_instruction159(); + void CryptonightR_instruction160(); + void CryptonightR_instruction161(); + void CryptonightR_instruction162(); + void CryptonightR_instruction163(); + void CryptonightR_instruction164(); + void CryptonightR_instruction165(); + void CryptonightR_instruction166(); + void CryptonightR_instruction167(); + void CryptonightR_instruction168(); + void CryptonightR_instruction169(); + void CryptonightR_instruction170(); + void CryptonightR_instruction171(); + void CryptonightR_instruction172(); + void CryptonightR_instruction173(); + void CryptonightR_instruction174(); + void CryptonightR_instruction175(); + void CryptonightR_instruction176(); + void CryptonightR_instruction177(); + void CryptonightR_instruction178(); + void CryptonightR_instruction179(); + void CryptonightR_instruction180(); + void CryptonightR_instruction181(); + void CryptonightR_instruction182(); + void CryptonightR_instruction183(); + void CryptonightR_instruction184(); + void CryptonightR_instruction185(); + void CryptonightR_instruction186(); + void CryptonightR_instruction187(); + void CryptonightR_instruction188(); + void CryptonightR_instruction189(); + void CryptonightR_instruction190(); + void CryptonightR_instruction191(); + void CryptonightR_instruction192(); + void CryptonightR_instruction193(); + void CryptonightR_instruction194(); + void CryptonightR_instruction195(); + void CryptonightR_instruction196(); + void CryptonightR_instruction197(); + void CryptonightR_instruction198(); + void CryptonightR_instruction199(); + void CryptonightR_instruction200(); + void CryptonightR_instruction201(); + void CryptonightR_instruction202(); + void CryptonightR_instruction203(); + void CryptonightR_instruction204(); + void CryptonightR_instruction205(); + void CryptonightR_instruction206(); + void CryptonightR_instruction207(); + void CryptonightR_instruction208(); + void CryptonightR_instruction209(); + void CryptonightR_instruction210(); + void CryptonightR_instruction211(); + void CryptonightR_instruction212(); + void CryptonightR_instruction213(); + void CryptonightR_instruction214(); + void CryptonightR_instruction215(); + void CryptonightR_instruction216(); + void CryptonightR_instruction217(); + void CryptonightR_instruction218(); + void CryptonightR_instruction219(); + void CryptonightR_instruction220(); + void CryptonightR_instruction221(); + void CryptonightR_instruction222(); + void CryptonightR_instruction223(); + void CryptonightR_instruction224(); + void CryptonightR_instruction225(); + void CryptonightR_instruction226(); + void CryptonightR_instruction227(); + void CryptonightR_instruction228(); + void CryptonightR_instruction229(); + void CryptonightR_instruction230(); + void CryptonightR_instruction231(); + void CryptonightR_instruction232(); + void CryptonightR_instruction233(); + void CryptonightR_instruction234(); + void CryptonightR_instruction235(); + void CryptonightR_instruction236(); + void CryptonightR_instruction237(); + void CryptonightR_instruction238(); + void CryptonightR_instruction239(); + void CryptonightR_instruction240(); + void CryptonightR_instruction241(); + void CryptonightR_instruction242(); + void CryptonightR_instruction243(); + void CryptonightR_instruction244(); + void CryptonightR_instruction245(); + void CryptonightR_instruction246(); + void CryptonightR_instruction247(); + void CryptonightR_instruction248(); + void CryptonightR_instruction249(); + void CryptonightR_instruction250(); + void CryptonightR_instruction251(); + void CryptonightR_instruction252(); + void CryptonightR_instruction253(); + void CryptonightR_instruction254(); + void CryptonightR_instruction255(); + void CryptonightR_instruction256(); + void CryptonightR_instruction_mov0(); + void CryptonightR_instruction_mov1(); + void CryptonightR_instruction_mov2(); + void CryptonightR_instruction_mov3(); + void CryptonightR_instruction_mov4(); + void CryptonightR_instruction_mov5(); + void CryptonightR_instruction_mov6(); + void CryptonightR_instruction_mov7(); + void CryptonightR_instruction_mov8(); + void CryptonightR_instruction_mov9(); + void CryptonightR_instruction_mov10(); + void CryptonightR_instruction_mov11(); + void CryptonightR_instruction_mov12(); + void CryptonightR_instruction_mov13(); + void CryptonightR_instruction_mov14(); + void CryptonightR_instruction_mov15(); + void CryptonightR_instruction_mov16(); + void CryptonightR_instruction_mov17(); + void CryptonightR_instruction_mov18(); + void CryptonightR_instruction_mov19(); + void CryptonightR_instruction_mov20(); + void CryptonightR_instruction_mov21(); + void CryptonightR_instruction_mov22(); + void CryptonightR_instruction_mov23(); + void CryptonightR_instruction_mov24(); + void CryptonightR_instruction_mov25(); + void CryptonightR_instruction_mov26(); + void CryptonightR_instruction_mov27(); + void CryptonightR_instruction_mov28(); + void CryptonightR_instruction_mov29(); + void CryptonightR_instruction_mov30(); + void CryptonightR_instruction_mov31(); + void CryptonightR_instruction_mov32(); + void CryptonightR_instruction_mov33(); + void CryptonightR_instruction_mov34(); + void CryptonightR_instruction_mov35(); + void CryptonightR_instruction_mov36(); + void CryptonightR_instruction_mov37(); + void CryptonightR_instruction_mov38(); + void CryptonightR_instruction_mov39(); + void CryptonightR_instruction_mov40(); + void CryptonightR_instruction_mov41(); + void CryptonightR_instruction_mov42(); + void CryptonightR_instruction_mov43(); + void CryptonightR_instruction_mov44(); + void CryptonightR_instruction_mov45(); + void CryptonightR_instruction_mov46(); + void CryptonightR_instruction_mov47(); + void CryptonightR_instruction_mov48(); + void CryptonightR_instruction_mov49(); + void CryptonightR_instruction_mov50(); + void CryptonightR_instruction_mov51(); + void CryptonightR_instruction_mov52(); + void CryptonightR_instruction_mov53(); + void CryptonightR_instruction_mov54(); + void CryptonightR_instruction_mov55(); + void CryptonightR_instruction_mov56(); + void CryptonightR_instruction_mov57(); + void CryptonightR_instruction_mov58(); + void CryptonightR_instruction_mov59(); + void CryptonightR_instruction_mov60(); + void CryptonightR_instruction_mov61(); + void CryptonightR_instruction_mov62(); + void CryptonightR_instruction_mov63(); + void CryptonightR_instruction_mov64(); + void CryptonightR_instruction_mov65(); + void CryptonightR_instruction_mov66(); + void CryptonightR_instruction_mov67(); + void CryptonightR_instruction_mov68(); + void CryptonightR_instruction_mov69(); + void CryptonightR_instruction_mov70(); + void CryptonightR_instruction_mov71(); + void CryptonightR_instruction_mov72(); + void CryptonightR_instruction_mov73(); + void CryptonightR_instruction_mov74(); + void CryptonightR_instruction_mov75(); + void CryptonightR_instruction_mov76(); + void CryptonightR_instruction_mov77(); + void CryptonightR_instruction_mov78(); + void CryptonightR_instruction_mov79(); + void CryptonightR_instruction_mov80(); + void CryptonightR_instruction_mov81(); + void CryptonightR_instruction_mov82(); + void CryptonightR_instruction_mov83(); + void CryptonightR_instruction_mov84(); + void CryptonightR_instruction_mov85(); + void CryptonightR_instruction_mov86(); + void CryptonightR_instruction_mov87(); + void CryptonightR_instruction_mov88(); + void CryptonightR_instruction_mov89(); + void CryptonightR_instruction_mov90(); + void CryptonightR_instruction_mov91(); + void CryptonightR_instruction_mov92(); + void CryptonightR_instruction_mov93(); + void CryptonightR_instruction_mov94(); + void CryptonightR_instruction_mov95(); + void CryptonightR_instruction_mov96(); + void CryptonightR_instruction_mov97(); + void CryptonightR_instruction_mov98(); + void CryptonightR_instruction_mov99(); + void CryptonightR_instruction_mov100(); + void CryptonightR_instruction_mov101(); + void CryptonightR_instruction_mov102(); + void CryptonightR_instruction_mov103(); + void CryptonightR_instruction_mov104(); + void CryptonightR_instruction_mov105(); + void CryptonightR_instruction_mov106(); + void CryptonightR_instruction_mov107(); + void CryptonightR_instruction_mov108(); + void CryptonightR_instruction_mov109(); + void CryptonightR_instruction_mov110(); + void CryptonightR_instruction_mov111(); + void CryptonightR_instruction_mov112(); + void CryptonightR_instruction_mov113(); + void CryptonightR_instruction_mov114(); + void CryptonightR_instruction_mov115(); + void CryptonightR_instruction_mov116(); + void CryptonightR_instruction_mov117(); + void CryptonightR_instruction_mov118(); + void CryptonightR_instruction_mov119(); + void CryptonightR_instruction_mov120(); + void CryptonightR_instruction_mov121(); + void CryptonightR_instruction_mov122(); + void CryptonightR_instruction_mov123(); + void CryptonightR_instruction_mov124(); + void CryptonightR_instruction_mov125(); + void CryptonightR_instruction_mov126(); + void CryptonightR_instruction_mov127(); + void CryptonightR_instruction_mov128(); + void CryptonightR_instruction_mov129(); + void CryptonightR_instruction_mov130(); + void CryptonightR_instruction_mov131(); + void CryptonightR_instruction_mov132(); + void CryptonightR_instruction_mov133(); + void CryptonightR_instruction_mov134(); + void CryptonightR_instruction_mov135(); + void CryptonightR_instruction_mov136(); + void CryptonightR_instruction_mov137(); + void CryptonightR_instruction_mov138(); + void CryptonightR_instruction_mov139(); + void CryptonightR_instruction_mov140(); + void CryptonightR_instruction_mov141(); + void CryptonightR_instruction_mov142(); + void CryptonightR_instruction_mov143(); + void CryptonightR_instruction_mov144(); + void CryptonightR_instruction_mov145(); + void CryptonightR_instruction_mov146(); + void CryptonightR_instruction_mov147(); + void CryptonightR_instruction_mov148(); + void CryptonightR_instruction_mov149(); + void CryptonightR_instruction_mov150(); + void CryptonightR_instruction_mov151(); + void CryptonightR_instruction_mov152(); + void CryptonightR_instruction_mov153(); + void CryptonightR_instruction_mov154(); + void CryptonightR_instruction_mov155(); + void CryptonightR_instruction_mov156(); + void CryptonightR_instruction_mov157(); + void CryptonightR_instruction_mov158(); + void CryptonightR_instruction_mov159(); + void CryptonightR_instruction_mov160(); + void CryptonightR_instruction_mov161(); + void CryptonightR_instruction_mov162(); + void CryptonightR_instruction_mov163(); + void CryptonightR_instruction_mov164(); + void CryptonightR_instruction_mov165(); + void CryptonightR_instruction_mov166(); + void CryptonightR_instruction_mov167(); + void CryptonightR_instruction_mov168(); + void CryptonightR_instruction_mov169(); + void CryptonightR_instruction_mov170(); + void CryptonightR_instruction_mov171(); + void CryptonightR_instruction_mov172(); + void CryptonightR_instruction_mov173(); + void CryptonightR_instruction_mov174(); + void CryptonightR_instruction_mov175(); + void CryptonightR_instruction_mov176(); + void CryptonightR_instruction_mov177(); + void CryptonightR_instruction_mov178(); + void CryptonightR_instruction_mov179(); + void CryptonightR_instruction_mov180(); + void CryptonightR_instruction_mov181(); + void CryptonightR_instruction_mov182(); + void CryptonightR_instruction_mov183(); + void CryptonightR_instruction_mov184(); + void CryptonightR_instruction_mov185(); + void CryptonightR_instruction_mov186(); + void CryptonightR_instruction_mov187(); + void CryptonightR_instruction_mov188(); + void CryptonightR_instruction_mov189(); + void CryptonightR_instruction_mov190(); + void CryptonightR_instruction_mov191(); + void CryptonightR_instruction_mov192(); + void CryptonightR_instruction_mov193(); + void CryptonightR_instruction_mov194(); + void CryptonightR_instruction_mov195(); + void CryptonightR_instruction_mov196(); + void CryptonightR_instruction_mov197(); + void CryptonightR_instruction_mov198(); + void CryptonightR_instruction_mov199(); + void CryptonightR_instruction_mov200(); + void CryptonightR_instruction_mov201(); + void CryptonightR_instruction_mov202(); + void CryptonightR_instruction_mov203(); + void CryptonightR_instruction_mov204(); + void CryptonightR_instruction_mov205(); + void CryptonightR_instruction_mov206(); + void CryptonightR_instruction_mov207(); + void CryptonightR_instruction_mov208(); + void CryptonightR_instruction_mov209(); + void CryptonightR_instruction_mov210(); + void CryptonightR_instruction_mov211(); + void CryptonightR_instruction_mov212(); + void CryptonightR_instruction_mov213(); + void CryptonightR_instruction_mov214(); + void CryptonightR_instruction_mov215(); + void CryptonightR_instruction_mov216(); + void CryptonightR_instruction_mov217(); + void CryptonightR_instruction_mov218(); + void CryptonightR_instruction_mov219(); + void CryptonightR_instruction_mov220(); + void CryptonightR_instruction_mov221(); + void CryptonightR_instruction_mov222(); + void CryptonightR_instruction_mov223(); + void CryptonightR_instruction_mov224(); + void CryptonightR_instruction_mov225(); + void CryptonightR_instruction_mov226(); + void CryptonightR_instruction_mov227(); + void CryptonightR_instruction_mov228(); + void CryptonightR_instruction_mov229(); + void CryptonightR_instruction_mov230(); + void CryptonightR_instruction_mov231(); + void CryptonightR_instruction_mov232(); + void CryptonightR_instruction_mov233(); + void CryptonightR_instruction_mov234(); + void CryptonightR_instruction_mov235(); + void CryptonightR_instruction_mov236(); + void CryptonightR_instruction_mov237(); + void CryptonightR_instruction_mov238(); + void CryptonightR_instruction_mov239(); + void CryptonightR_instruction_mov240(); + void CryptonightR_instruction_mov241(); + void CryptonightR_instruction_mov242(); + void CryptonightR_instruction_mov243(); + void CryptonightR_instruction_mov244(); + void CryptonightR_instruction_mov245(); + void CryptonightR_instruction_mov246(); + void CryptonightR_instruction_mov247(); + void CryptonightR_instruction_mov248(); + void CryptonightR_instruction_mov249(); + void CryptonightR_instruction_mov250(); + void CryptonightR_instruction_mov251(); + void CryptonightR_instruction_mov252(); + void CryptonightR_instruction_mov253(); + void CryptonightR_instruction_mov254(); + void CryptonightR_instruction_mov255(); + void CryptonightR_instruction_mov256(); +} + +const void_func instructions[257] = { + CryptonightR_instruction0, + CryptonightR_instruction1, + CryptonightR_instruction2, + CryptonightR_instruction3, + CryptonightR_instruction4, + CryptonightR_instruction5, + CryptonightR_instruction6, + CryptonightR_instruction7, + CryptonightR_instruction8, + CryptonightR_instruction9, + CryptonightR_instruction10, + CryptonightR_instruction11, + CryptonightR_instruction12, + CryptonightR_instruction13, + CryptonightR_instruction14, + CryptonightR_instruction15, + CryptonightR_instruction16, + CryptonightR_instruction17, + CryptonightR_instruction18, + CryptonightR_instruction19, + CryptonightR_instruction20, + CryptonightR_instruction21, + CryptonightR_instruction22, + CryptonightR_instruction23, + CryptonightR_instruction24, + CryptonightR_instruction25, + CryptonightR_instruction26, + CryptonightR_instruction27, + CryptonightR_instruction28, + CryptonightR_instruction29, + CryptonightR_instruction30, + CryptonightR_instruction31, + CryptonightR_instruction32, + CryptonightR_instruction33, + CryptonightR_instruction34, + CryptonightR_instruction35, + CryptonightR_instruction36, + CryptonightR_instruction37, + CryptonightR_instruction38, + CryptonightR_instruction39, + CryptonightR_instruction40, + CryptonightR_instruction41, + CryptonightR_instruction42, + CryptonightR_instruction43, + CryptonightR_instruction44, + CryptonightR_instruction45, + CryptonightR_instruction46, + CryptonightR_instruction47, + CryptonightR_instruction48, + CryptonightR_instruction49, + CryptonightR_instruction50, + CryptonightR_instruction51, + CryptonightR_instruction52, + CryptonightR_instruction53, + CryptonightR_instruction54, + CryptonightR_instruction55, + CryptonightR_instruction56, + CryptonightR_instruction57, + CryptonightR_instruction58, + CryptonightR_instruction59, + CryptonightR_instruction60, + CryptonightR_instruction61, + CryptonightR_instruction62, + CryptonightR_instruction63, + CryptonightR_instruction64, + CryptonightR_instruction65, + CryptonightR_instruction66, + CryptonightR_instruction67, + CryptonightR_instruction68, + CryptonightR_instruction69, + CryptonightR_instruction70, + CryptonightR_instruction71, + CryptonightR_instruction72, + CryptonightR_instruction73, + CryptonightR_instruction74, + CryptonightR_instruction75, + CryptonightR_instruction76, + CryptonightR_instruction77, + CryptonightR_instruction78, + CryptonightR_instruction79, + CryptonightR_instruction80, + CryptonightR_instruction81, + CryptonightR_instruction82, + CryptonightR_instruction83, + CryptonightR_instruction84, + CryptonightR_instruction85, + CryptonightR_instruction86, + CryptonightR_instruction87, + CryptonightR_instruction88, + CryptonightR_instruction89, + CryptonightR_instruction90, + CryptonightR_instruction91, + CryptonightR_instruction92, + CryptonightR_instruction93, + CryptonightR_instruction94, + CryptonightR_instruction95, + CryptonightR_instruction96, + CryptonightR_instruction97, + CryptonightR_instruction98, + CryptonightR_instruction99, + CryptonightR_instruction100, + CryptonightR_instruction101, + CryptonightR_instruction102, + CryptonightR_instruction103, + CryptonightR_instruction104, + CryptonightR_instruction105, + CryptonightR_instruction106, + CryptonightR_instruction107, + CryptonightR_instruction108, + CryptonightR_instruction109, + CryptonightR_instruction110, + CryptonightR_instruction111, + CryptonightR_instruction112, + CryptonightR_instruction113, + CryptonightR_instruction114, + CryptonightR_instruction115, + CryptonightR_instruction116, + CryptonightR_instruction117, + CryptonightR_instruction118, + CryptonightR_instruction119, + CryptonightR_instruction120, + CryptonightR_instruction121, + CryptonightR_instruction122, + CryptonightR_instruction123, + CryptonightR_instruction124, + CryptonightR_instruction125, + CryptonightR_instruction126, + CryptonightR_instruction127, + CryptonightR_instruction128, + CryptonightR_instruction129, + CryptonightR_instruction130, + CryptonightR_instruction131, + CryptonightR_instruction132, + CryptonightR_instruction133, + CryptonightR_instruction134, + CryptonightR_instruction135, + CryptonightR_instruction136, + CryptonightR_instruction137, + CryptonightR_instruction138, + CryptonightR_instruction139, + CryptonightR_instruction140, + CryptonightR_instruction141, + CryptonightR_instruction142, + CryptonightR_instruction143, + CryptonightR_instruction144, + CryptonightR_instruction145, + CryptonightR_instruction146, + CryptonightR_instruction147, + CryptonightR_instruction148, + CryptonightR_instruction149, + CryptonightR_instruction150, + CryptonightR_instruction151, + CryptonightR_instruction152, + CryptonightR_instruction153, + CryptonightR_instruction154, + CryptonightR_instruction155, + CryptonightR_instruction156, + CryptonightR_instruction157, + CryptonightR_instruction158, + CryptonightR_instruction159, + CryptonightR_instruction160, + CryptonightR_instruction161, + CryptonightR_instruction162, + CryptonightR_instruction163, + CryptonightR_instruction164, + CryptonightR_instruction165, + CryptonightR_instruction166, + CryptonightR_instruction167, + CryptonightR_instruction168, + CryptonightR_instruction169, + CryptonightR_instruction170, + CryptonightR_instruction171, + CryptonightR_instruction172, + CryptonightR_instruction173, + CryptonightR_instruction174, + CryptonightR_instruction175, + CryptonightR_instruction176, + CryptonightR_instruction177, + CryptonightR_instruction178, + CryptonightR_instruction179, + CryptonightR_instruction180, + CryptonightR_instruction181, + CryptonightR_instruction182, + CryptonightR_instruction183, + CryptonightR_instruction184, + CryptonightR_instruction185, + CryptonightR_instruction186, + CryptonightR_instruction187, + CryptonightR_instruction188, + CryptonightR_instruction189, + CryptonightR_instruction190, + CryptonightR_instruction191, + CryptonightR_instruction192, + CryptonightR_instruction193, + CryptonightR_instruction194, + CryptonightR_instruction195, + CryptonightR_instruction196, + CryptonightR_instruction197, + CryptonightR_instruction198, + CryptonightR_instruction199, + CryptonightR_instruction200, + CryptonightR_instruction201, + CryptonightR_instruction202, + CryptonightR_instruction203, + CryptonightR_instruction204, + CryptonightR_instruction205, + CryptonightR_instruction206, + CryptonightR_instruction207, + CryptonightR_instruction208, + CryptonightR_instruction209, + CryptonightR_instruction210, + CryptonightR_instruction211, + CryptonightR_instruction212, + CryptonightR_instruction213, + CryptonightR_instruction214, + CryptonightR_instruction215, + CryptonightR_instruction216, + CryptonightR_instruction217, + CryptonightR_instruction218, + CryptonightR_instruction219, + CryptonightR_instruction220, + CryptonightR_instruction221, + CryptonightR_instruction222, + CryptonightR_instruction223, + CryptonightR_instruction224, + CryptonightR_instruction225, + CryptonightR_instruction226, + CryptonightR_instruction227, + CryptonightR_instruction228, + CryptonightR_instruction229, + CryptonightR_instruction230, + CryptonightR_instruction231, + CryptonightR_instruction232, + CryptonightR_instruction233, + CryptonightR_instruction234, + CryptonightR_instruction235, + CryptonightR_instruction236, + CryptonightR_instruction237, + CryptonightR_instruction238, + CryptonightR_instruction239, + CryptonightR_instruction240, + CryptonightR_instruction241, + CryptonightR_instruction242, + CryptonightR_instruction243, + CryptonightR_instruction244, + CryptonightR_instruction245, + CryptonightR_instruction246, + CryptonightR_instruction247, + CryptonightR_instruction248, + CryptonightR_instruction249, + CryptonightR_instruction250, + CryptonightR_instruction251, + CryptonightR_instruction252, + CryptonightR_instruction253, + CryptonightR_instruction254, + CryptonightR_instruction255, + CryptonightR_instruction256, +}; + +const void_func instructions_mov[257] = { + CryptonightR_instruction_mov0, + CryptonightR_instruction_mov1, + CryptonightR_instruction_mov2, + CryptonightR_instruction_mov3, + CryptonightR_instruction_mov4, + CryptonightR_instruction_mov5, + CryptonightR_instruction_mov6, + CryptonightR_instruction_mov7, + CryptonightR_instruction_mov8, + CryptonightR_instruction_mov9, + CryptonightR_instruction_mov10, + CryptonightR_instruction_mov11, + CryptonightR_instruction_mov12, + CryptonightR_instruction_mov13, + CryptonightR_instruction_mov14, + CryptonightR_instruction_mov15, + CryptonightR_instruction_mov16, + CryptonightR_instruction_mov17, + CryptonightR_instruction_mov18, + CryptonightR_instruction_mov19, + CryptonightR_instruction_mov20, + CryptonightR_instruction_mov21, + CryptonightR_instruction_mov22, + CryptonightR_instruction_mov23, + CryptonightR_instruction_mov24, + CryptonightR_instruction_mov25, + CryptonightR_instruction_mov26, + CryptonightR_instruction_mov27, + CryptonightR_instruction_mov28, + CryptonightR_instruction_mov29, + CryptonightR_instruction_mov30, + CryptonightR_instruction_mov31, + CryptonightR_instruction_mov32, + CryptonightR_instruction_mov33, + CryptonightR_instruction_mov34, + CryptonightR_instruction_mov35, + CryptonightR_instruction_mov36, + CryptonightR_instruction_mov37, + CryptonightR_instruction_mov38, + CryptonightR_instruction_mov39, + CryptonightR_instruction_mov40, + CryptonightR_instruction_mov41, + CryptonightR_instruction_mov42, + CryptonightR_instruction_mov43, + CryptonightR_instruction_mov44, + CryptonightR_instruction_mov45, + CryptonightR_instruction_mov46, + CryptonightR_instruction_mov47, + CryptonightR_instruction_mov48, + CryptonightR_instruction_mov49, + CryptonightR_instruction_mov50, + CryptonightR_instruction_mov51, + CryptonightR_instruction_mov52, + CryptonightR_instruction_mov53, + CryptonightR_instruction_mov54, + CryptonightR_instruction_mov55, + CryptonightR_instruction_mov56, + CryptonightR_instruction_mov57, + CryptonightR_instruction_mov58, + CryptonightR_instruction_mov59, + CryptonightR_instruction_mov60, + CryptonightR_instruction_mov61, + CryptonightR_instruction_mov62, + CryptonightR_instruction_mov63, + CryptonightR_instruction_mov64, + CryptonightR_instruction_mov65, + CryptonightR_instruction_mov66, + CryptonightR_instruction_mov67, + CryptonightR_instruction_mov68, + CryptonightR_instruction_mov69, + CryptonightR_instruction_mov70, + CryptonightR_instruction_mov71, + CryptonightR_instruction_mov72, + CryptonightR_instruction_mov73, + CryptonightR_instruction_mov74, + CryptonightR_instruction_mov75, + CryptonightR_instruction_mov76, + CryptonightR_instruction_mov77, + CryptonightR_instruction_mov78, + CryptonightR_instruction_mov79, + CryptonightR_instruction_mov80, + CryptonightR_instruction_mov81, + CryptonightR_instruction_mov82, + CryptonightR_instruction_mov83, + CryptonightR_instruction_mov84, + CryptonightR_instruction_mov85, + CryptonightR_instruction_mov86, + CryptonightR_instruction_mov87, + CryptonightR_instruction_mov88, + CryptonightR_instruction_mov89, + CryptonightR_instruction_mov90, + CryptonightR_instruction_mov91, + CryptonightR_instruction_mov92, + CryptonightR_instruction_mov93, + CryptonightR_instruction_mov94, + CryptonightR_instruction_mov95, + CryptonightR_instruction_mov96, + CryptonightR_instruction_mov97, + CryptonightR_instruction_mov98, + CryptonightR_instruction_mov99, + CryptonightR_instruction_mov100, + CryptonightR_instruction_mov101, + CryptonightR_instruction_mov102, + CryptonightR_instruction_mov103, + CryptonightR_instruction_mov104, + CryptonightR_instruction_mov105, + CryptonightR_instruction_mov106, + CryptonightR_instruction_mov107, + CryptonightR_instruction_mov108, + CryptonightR_instruction_mov109, + CryptonightR_instruction_mov110, + CryptonightR_instruction_mov111, + CryptonightR_instruction_mov112, + CryptonightR_instruction_mov113, + CryptonightR_instruction_mov114, + CryptonightR_instruction_mov115, + CryptonightR_instruction_mov116, + CryptonightR_instruction_mov117, + CryptonightR_instruction_mov118, + CryptonightR_instruction_mov119, + CryptonightR_instruction_mov120, + CryptonightR_instruction_mov121, + CryptonightR_instruction_mov122, + CryptonightR_instruction_mov123, + CryptonightR_instruction_mov124, + CryptonightR_instruction_mov125, + CryptonightR_instruction_mov126, + CryptonightR_instruction_mov127, + CryptonightR_instruction_mov128, + CryptonightR_instruction_mov129, + CryptonightR_instruction_mov130, + CryptonightR_instruction_mov131, + CryptonightR_instruction_mov132, + CryptonightR_instruction_mov133, + CryptonightR_instruction_mov134, + CryptonightR_instruction_mov135, + CryptonightR_instruction_mov136, + CryptonightR_instruction_mov137, + CryptonightR_instruction_mov138, + CryptonightR_instruction_mov139, + CryptonightR_instruction_mov140, + CryptonightR_instruction_mov141, + CryptonightR_instruction_mov142, + CryptonightR_instruction_mov143, + CryptonightR_instruction_mov144, + CryptonightR_instruction_mov145, + CryptonightR_instruction_mov146, + CryptonightR_instruction_mov147, + CryptonightR_instruction_mov148, + CryptonightR_instruction_mov149, + CryptonightR_instruction_mov150, + CryptonightR_instruction_mov151, + CryptonightR_instruction_mov152, + CryptonightR_instruction_mov153, + CryptonightR_instruction_mov154, + CryptonightR_instruction_mov155, + CryptonightR_instruction_mov156, + CryptonightR_instruction_mov157, + CryptonightR_instruction_mov158, + CryptonightR_instruction_mov159, + CryptonightR_instruction_mov160, + CryptonightR_instruction_mov161, + CryptonightR_instruction_mov162, + CryptonightR_instruction_mov163, + CryptonightR_instruction_mov164, + CryptonightR_instruction_mov165, + CryptonightR_instruction_mov166, + CryptonightR_instruction_mov167, + CryptonightR_instruction_mov168, + CryptonightR_instruction_mov169, + CryptonightR_instruction_mov170, + CryptonightR_instruction_mov171, + CryptonightR_instruction_mov172, + CryptonightR_instruction_mov173, + CryptonightR_instruction_mov174, + CryptonightR_instruction_mov175, + CryptonightR_instruction_mov176, + CryptonightR_instruction_mov177, + CryptonightR_instruction_mov178, + CryptonightR_instruction_mov179, + CryptonightR_instruction_mov180, + CryptonightR_instruction_mov181, + CryptonightR_instruction_mov182, + CryptonightR_instruction_mov183, + CryptonightR_instruction_mov184, + CryptonightR_instruction_mov185, + CryptonightR_instruction_mov186, + CryptonightR_instruction_mov187, + CryptonightR_instruction_mov188, + CryptonightR_instruction_mov189, + CryptonightR_instruction_mov190, + CryptonightR_instruction_mov191, + CryptonightR_instruction_mov192, + CryptonightR_instruction_mov193, + CryptonightR_instruction_mov194, + CryptonightR_instruction_mov195, + CryptonightR_instruction_mov196, + CryptonightR_instruction_mov197, + CryptonightR_instruction_mov198, + CryptonightR_instruction_mov199, + CryptonightR_instruction_mov200, + CryptonightR_instruction_mov201, + CryptonightR_instruction_mov202, + CryptonightR_instruction_mov203, + CryptonightR_instruction_mov204, + CryptonightR_instruction_mov205, + CryptonightR_instruction_mov206, + CryptonightR_instruction_mov207, + CryptonightR_instruction_mov208, + CryptonightR_instruction_mov209, + CryptonightR_instruction_mov210, + CryptonightR_instruction_mov211, + CryptonightR_instruction_mov212, + CryptonightR_instruction_mov213, + CryptonightR_instruction_mov214, + CryptonightR_instruction_mov215, + CryptonightR_instruction_mov216, + CryptonightR_instruction_mov217, + CryptonightR_instruction_mov218, + CryptonightR_instruction_mov219, + CryptonightR_instruction_mov220, + CryptonightR_instruction_mov221, + CryptonightR_instruction_mov222, + CryptonightR_instruction_mov223, + CryptonightR_instruction_mov224, + CryptonightR_instruction_mov225, + CryptonightR_instruction_mov226, + CryptonightR_instruction_mov227, + CryptonightR_instruction_mov228, + CryptonightR_instruction_mov229, + CryptonightR_instruction_mov230, + CryptonightR_instruction_mov231, + CryptonightR_instruction_mov232, + CryptonightR_instruction_mov233, + CryptonightR_instruction_mov234, + CryptonightR_instruction_mov235, + CryptonightR_instruction_mov236, + CryptonightR_instruction_mov237, + CryptonightR_instruction_mov238, + CryptonightR_instruction_mov239, + CryptonightR_instruction_mov240, + CryptonightR_instruction_mov241, + CryptonightR_instruction_mov242, + CryptonightR_instruction_mov243, + CryptonightR_instruction_mov244, + CryptonightR_instruction_mov245, + CryptonightR_instruction_mov246, + CryptonightR_instruction_mov247, + CryptonightR_instruction_mov248, + CryptonightR_instruction_mov249, + CryptonightR_instruction_mov250, + CryptonightR_instruction_mov251, + CryptonightR_instruction_mov252, + CryptonightR_instruction_mov253, + CryptonightR_instruction_mov254, + CryptonightR_instruction_mov255, + CryptonightR_instruction_mov256, +}; diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.inc b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.inc new file mode 100644 index 000000000..b54486a57 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.inc @@ -0,0 +1,529 @@ +PUBLIC FN_PREFIX(CryptonightR_template_part1) +PUBLIC FN_PREFIX(CryptonightR_template_mainloop) +PUBLIC FN_PREFIX(CryptonightR_template_part2) +PUBLIC FN_PREFIX(CryptonightR_template_part3) +PUBLIC FN_PREFIX(CryptonightR_template_end) +PUBLIC FN_PREFIX(CryptonightR_template_double_part1) +PUBLIC FN_PREFIX(CryptonightR_template_double_mainloop) +PUBLIC FN_PREFIX(CryptonightR_template_double_part2) +PUBLIC FN_PREFIX(CryptonightR_template_double_part3) +PUBLIC FN_PREFIX(CryptonightR_template_double_part4) +PUBLIC FN_PREFIX(CryptonightR_template_double_end) + +ALIGN(64) +FN_PREFIX(CryptonightR_template_part1): + mov QWORD PTR [rsp+16], rbx + mov QWORD PTR [rsp+24], rbp + mov QWORD PTR [rsp+32], rsi + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + push rdi + sub rsp, 64 + mov r12, rcx + mov r8, QWORD PTR [r12+32] + mov rdx, r12 + xor r8, QWORD PTR [r12] + mov r15, QWORD PTR [r12+40] + mov r9, r8 + xor r15, QWORD PTR [r12+8] + mov r11, QWORD PTR [r12+224] + mov r12, QWORD PTR [r12+56] + xor r12, QWORD PTR [rdx+24] + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + movaps XMMWORD PTR [rsp+48], xmm6 + movq xmm0, r12 + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+16], xmm8 + movaps XMMWORD PTR [rsp], xmm9 + mov r12, QWORD PTR [rdx+88] + xor r12, QWORD PTR [rdx+72] + movq xmm6, rax + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm6, xmm0 + and r9d, 2097136 + movq xmm0, r12 + movq xmm7, rax + punpcklqdq xmm7, xmm0 + mov r10d, r9d + movq xmm9, rsp + mov rsp, r8 + mov r8d, 524288 + + mov ebx, [rdx+96] + mov esi, [rdx+100] + mov edi, [rdx+104] + mov ebp, [rdx+108] + + ALIGN(64) +FN_PREFIX(CryptonightR_template_mainloop): + movdqa xmm5, XMMWORD PTR [r9+r11] + movq xmm0, r15 + movq xmm4, rsp + punpcklqdq xmm4, xmm0 + lea rdx, QWORD PTR [r9+r11] + + aesenc xmm5, xmm4 + + mov r12d, r9d + mov eax, r9d + xor r9d, 48 + xor r12d, 16 + xor eax, 32 + movdqu xmm0, XMMWORD PTR [r9+r11] + movaps xmm3, xmm0 + movdqu xmm2, XMMWORD PTR [r12+r11] + movdqu xmm1, XMMWORD PTR [rax+r11] + pxor xmm0, xmm2 + pxor xmm5, xmm1 + pxor xmm5, xmm0 + paddq xmm3, xmm7 + paddq xmm2, xmm6 + paddq xmm1, xmm4 + movdqu XMMWORD PTR [r12+r11], xmm3 + movdqu XMMWORD PTR [rax+r11], xmm2 + movdqu XMMWORD PTR [r9+r11], xmm1 + + movq r12, xmm5 + movd r10d, xmm5 + and r10d, 2097136 + + movdqa xmm0, xmm5 + pxor xmm0, xmm6 + movdqu XMMWORD PTR [rdx], xmm0 + + lea r13d, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or r13, rdx + + xor r13, QWORD PTR [r10+r11] + mov r14, QWORD PTR [r10+r11+8] + + movd eax, xmm6 + movd edx, xmm7 + pextrd r9d, xmm7, 2 + +FN_PREFIX(CryptonightR_template_part2): + mov eax, edi + mov edx, ebp + shl rdx, 32 + or rax, rdx + xor rsp, rax + + mov eax, ebx + mov edx, esi + shl rdx, 32 + or rax, rdx + xor r15, rax + + mov rax, r13 + mul r12 + + mov r9d, r10d + mov r12d, r10d + xor r9d, 16 + xor r12d, 32 + xor r10d, 48 + movdqa xmm1, XMMWORD PTR [r12+r11] + movaps xmm3, xmm1 + movdqa xmm2, XMMWORD PTR [r9+r11] + movdqa xmm0, XMMWORD PTR [r10+r11] + pxor xmm1, xmm2 + pxor xmm5, xmm0 + pxor xmm5, xmm1 + paddq xmm3, xmm4 + paddq xmm2, xmm6 + paddq xmm0, xmm7 + movdqu XMMWORD PTR [r9+r11], xmm0 + movdqu XMMWORD PTR [r12+r11], xmm2 + movdqu XMMWORD PTR [r10+r11], xmm3 + + movdqa xmm7, xmm6 + add r15, rax + add rsp, rdx + xor r10, 48 + mov QWORD PTR [r10+r11], rsp + xor rsp, r13 + mov r9d, esp + mov QWORD PTR [r10+r11+8], r15 + and r9d, 2097136 + xor r15, r14 + movdqa xmm6, xmm5 + dec r8d + jnz FN_PREFIX(CryptonightR_template_mainloop) + +FN_PREFIX(CryptonightR_template_part3): + movq rsp, xmm9 + + mov rbx, QWORD PTR [rsp+136] + mov rbp, QWORD PTR [rsp+144] + mov rsi, QWORD PTR [rsp+152] + movaps xmm6, XMMWORD PTR [rsp+48] + movaps xmm7, XMMWORD PTR [rsp+32] + movaps xmm8, XMMWORD PTR [rsp+16] + movaps xmm9, XMMWORD PTR [rsp] + add rsp, 64 + pop rdi + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + ret 0 +FN_PREFIX(CryptonightR_template_end): + +ALIGN(64) +FN_PREFIX(CryptonightR_template_double_part1): + mov QWORD PTR [rsp+24], rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 320 + mov r14, QWORD PTR [rcx+32] + mov r8, rcx + xor r14, QWORD PTR [rcx] + mov r12, QWORD PTR [rcx+40] + mov ebx, r14d + mov rsi, QWORD PTR [rcx+224] + and ebx, 2097136 + xor r12, QWORD PTR [rcx+8] + mov rcx, QWORD PTR [rcx+56] + xor rcx, QWORD PTR [r8+24] + mov rax, QWORD PTR [r8+48] + xor rax, QWORD PTR [r8+16] + mov r15, QWORD PTR [rdx+32] + xor r15, QWORD PTR [rdx] + movq xmm0, rcx + mov rcx, QWORD PTR [r8+88] + xor rcx, QWORD PTR [r8+72] + mov r13, QWORD PTR [rdx+40] + mov rdi, QWORD PTR [rdx+224] + xor r13, QWORD PTR [rdx+8] + movaps XMMWORD PTR [rsp+160], xmm6 + movaps XMMWORD PTR [rsp+176], xmm7 + movaps XMMWORD PTR [rsp+192], xmm8 + movaps XMMWORD PTR [rsp+208], xmm9 + movaps XMMWORD PTR [rsp+224], xmm10 + movaps XMMWORD PTR [rsp+240], xmm11 + movaps XMMWORD PTR [rsp+256], xmm12 + movaps XMMWORD PTR [rsp+272], xmm13 + movaps XMMWORD PTR [rsp+288], xmm14 + movaps XMMWORD PTR [rsp+304], xmm15 + movq xmm7, rax + mov rax, QWORD PTR [r8+80] + xor rax, QWORD PTR [r8+64] + + movaps xmm1, XMMWORD PTR [rdx+96] + movaps xmm2, XMMWORD PTR [r8+96] + movaps XMMWORD PTR [rsp], xmm1 + movaps XMMWORD PTR [rsp+16], xmm2 + + mov r8d, r15d + punpcklqdq xmm7, xmm0 + movq xmm0, rcx + mov rcx, QWORD PTR [rdx+56] + xor rcx, QWORD PTR [rdx+24] + movq xmm9, rax + mov QWORD PTR [rsp+128], rsi + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + punpcklqdq xmm9, xmm0 + movq xmm0, rcx + mov rcx, QWORD PTR [rdx+88] + xor rcx, QWORD PTR [rdx+72] + movq xmm8, rax + mov QWORD PTR [rsp+136], rdi + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm8, xmm0 + and r8d, 2097136 + movq xmm0, rcx + mov r11d, 524288 + movq xmm10, rax + punpcklqdq xmm10, xmm0 + + movq xmm14, QWORD PTR [rsp+128] + movq xmm15, QWORD PTR [rsp+136] + + ALIGN(64) +FN_PREFIX(CryptonightR_template_double_mainloop): + movdqu xmm6, XMMWORD PTR [rbx+rsi] + movq xmm0, r12 + mov ecx, ebx + movq xmm3, r14 + punpcklqdq xmm3, xmm0 + xor ebx, 16 + aesenc xmm6, xmm3 + movq xmm4, r15 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + pxor xmm6, xmm0 + xor ebx, 48 + paddq xmm0, xmm7 + movdqu xmm1, XMMWORD PTR [rbx+rsi] + pxor xmm6, xmm1 + movdqu XMMWORD PTR [rbx+rsi], xmm0 + paddq xmm1, xmm3 + xor ebx, 16 + mov eax, ebx + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + pxor xmm6, xmm0 + movq rdx, xmm6 + movdqu XMMWORD PTR [rbx+rsi], xmm1 + paddq xmm0, xmm9 + movdqu XMMWORD PTR [rax+rsi], xmm0 + movdqa xmm0, xmm6 + pxor xmm0, xmm7 + movdqu XMMWORD PTR [rcx+rsi], xmm0 + mov esi, edx + movdqu xmm5, XMMWORD PTR [r8+rdi] + and esi, 2097136 + mov ecx, r8d + movq xmm0, r13 + punpcklqdq xmm4, xmm0 + xor r8d, 16 + aesenc xmm5, xmm4 + movdqu xmm0, XMMWORD PTR [r8+rdi] + pxor xmm5, xmm0 + xor r8d, 48 + paddq xmm0, xmm8 + movdqu xmm1, XMMWORD PTR [r8+rdi] + pxor xmm5, xmm1 + movdqu XMMWORD PTR [r8+rdi], xmm0 + paddq xmm1, xmm4 + xor r8d, 16 + mov eax, r8d + xor rax, 32 + movdqu xmm0, XMMWORD PTR [r8+rdi] + pxor xmm5, xmm0 + movdqu XMMWORD PTR [r8+rdi], xmm1 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rdi], xmm0 + movdqa xmm0, xmm5 + pxor xmm0, xmm8 + movdqu XMMWORD PTR [rcx+rdi], xmm0 + movq rdi, xmm5 + movq rcx, xmm14 + mov ebp, edi + mov r8, QWORD PTR [rcx+rsi] + mov r10, QWORD PTR [rcx+rsi+8] + lea r9, QWORD PTR [rcx+rsi] + xor esi, 16 + + movq xmm0, rsp + movq xmm1, rsi + movq xmm2, rdi + movq xmm11, rbp + movq xmm12, r15 + movq xmm13, rdx + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp+16] + mov esi, DWORD PTR [rsp+20] + mov edi, DWORD PTR [rsp+24] + mov ebp, DWORD PTR [rsp+28] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + xor r8, rax + + movd esp, xmm3 + pextrd r15d, xmm3, 2 + movd eax, xmm7 + movd edx, xmm9 + pextrd r9d, xmm9, 2 + +FN_PREFIX(CryptonightR_template_double_part2): + + mov eax, edi + mov edx, ebp + shl rdx, 32 + or rax, rdx + xor r14, rax + + mov eax, ebx + mov edx, esi + shl rdx, 32 + or rax, rdx + xor r12, rax + + movq rsp, xmm0 + mov DWORD PTR [rsp+16], ebx + mov DWORD PTR [rsp+20], esi + mov DWORD PTR [rsp+24], edi + mov DWORD PTR [rsp+28], ebp + + movq rsi, xmm1 + movq rdi, xmm2 + movq rbp, xmm11 + movq r15, xmm12 + movq rdx, xmm13 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rbx, r8 + mov rax, r8 + mul rdx + and ebp, 2097136 + mov r8, rax + movdqu xmm1, XMMWORD PTR [rcx+rsi] + pxor xmm6, xmm1 + xor esi, 48 + paddq xmm1, xmm7 + movdqu xmm2, XMMWORD PTR [rsi+rcx] + pxor xmm6, xmm2 + paddq xmm2, xmm3 + movdqu XMMWORD PTR [rsi+rcx], xmm1 + xor esi, 16 + mov eax, esi + mov rsi, rcx + movdqu xmm0, XMMWORD PTR [rax+rcx] + pxor xmm6, xmm0 + movdqu XMMWORD PTR [rax+rcx], xmm2 + paddq xmm0, xmm9 + add r12, r8 + xor rax, 32 + add r14, rdx + movdqa xmm9, xmm7 + movdqa xmm7, xmm6 + movdqu XMMWORD PTR [rax+rcx], xmm0 + mov QWORD PTR [r9+8], r12 + xor r12, r10 + mov QWORD PTR [r9], r14 + movq rcx, xmm15 + xor r14, rbx + mov r10d, ebp + mov ebx, r14d + xor ebp, 16 + and ebx, 2097136 + mov r8, QWORD PTR [r10+rcx] + mov r9, QWORD PTR [r10+rcx+8] + + movq xmm0, rsp + movq xmm1, rbx + movq xmm2, rsi + movq xmm11, rdi + movq xmm12, rbp + movq xmm13, r15 + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp] + mov esi, DWORD PTR [rsp+4] + mov edi, DWORD PTR [rsp+8] + mov ebp, DWORD PTR [rsp+12] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + + xor r8, rax + movq xmm3, r8 + + movd esp, xmm4 + pextrd r15d, xmm4, 2 + movd eax, xmm8 + movd edx, xmm10 + pextrd r9d, xmm10, 2 + +FN_PREFIX(CryptonightR_template_double_part3): + + movq r15, xmm13 + + mov eax, edi + mov edx, ebp + shl rdx, 32 + or rax, rdx + xor r15, rax + + mov eax, ebx + mov edx, esi + shl rdx, 32 + or rax, rdx + xor r13, rax + + movq rsp, xmm0 + mov DWORD PTR [rsp], ebx + mov DWORD PTR [rsp+4], esi + mov DWORD PTR [rsp+8], edi + mov DWORD PTR [rsp+12], ebp + + movq rbx, xmm1 + movq rsi, xmm2 + movq rdi, xmm11 + movq rbp, xmm12 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rax, r8 + mul rdi + mov rdi, rcx + mov r8, rax + movdqu xmm1, XMMWORD PTR [rbp+rcx] + pxor xmm5, xmm1 + xor ebp, 48 + paddq xmm1, xmm8 + add r13, r8 + movdqu xmm2, XMMWORD PTR [rbp+rcx] + pxor xmm5, xmm2 + add r15, rdx + movdqu XMMWORD PTR [rbp+rcx], xmm1 + paddq xmm2, xmm4 + xor ebp, 16 + mov eax, ebp + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbp+rcx] + pxor xmm5, xmm0 + movdqu XMMWORD PTR [rbp+rcx], xmm2 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rcx], xmm0 + movq rax, xmm3 + movdqa xmm10, xmm8 + mov QWORD PTR [r10+rcx], r15 + movdqa xmm8, xmm5 + xor r15, rax + mov QWORD PTR [r10+rcx+8], r13 + mov r8d, r15d + xor r13, r9 + and r8d, 2097136 + dec r11d + jnz FN_PREFIX(CryptonightR_template_double_mainloop) + +FN_PREFIX(CryptonightR_template_double_part4): + + mov rbx, QWORD PTR [rsp+400] + movaps xmm6, XMMWORD PTR [rsp+160] + movaps xmm7, XMMWORD PTR [rsp+176] + movaps xmm8, XMMWORD PTR [rsp+192] + movaps xmm9, XMMWORD PTR [rsp+208] + movaps xmm10, XMMWORD PTR [rsp+224] + movaps xmm11, XMMWORD PTR [rsp+240] + movaps xmm12, XMMWORD PTR [rsp+256] + movaps xmm13, XMMWORD PTR [rsp+272] + movaps xmm14, XMMWORD PTR [rsp+288] + movaps xmm15, XMMWORD PTR [rsp+304] + add rsp, 320 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + ret 0 +FN_PREFIX(CryptonightR_template_double_end): diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_template.inc b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_template.inc new file mode 100644 index 000000000..7183a659f --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_template.inc @@ -0,0 +1,486 @@ +PUBLIC FN_PREFIX(CryptonightWOW_template_part1) +PUBLIC FN_PREFIX(CryptonightWOW_template_mainloop) +PUBLIC FN_PREFIX(CryptonightWOW_template_part2) +PUBLIC FN_PREFIX(CryptonightWOW_template_part3) +PUBLIC FN_PREFIX(CryptonightWOW_template_end) +PUBLIC FN_PREFIX(CryptonightWOW_template_double_part1) +PUBLIC FN_PREFIX(CryptonightWOW_template_double_mainloop) +PUBLIC FN_PREFIX(CryptonightWOW_template_double_part2) +PUBLIC FN_PREFIX(CryptonightWOW_template_double_part3) +PUBLIC FN_PREFIX(CryptonightWOW_template_double_part4) +PUBLIC FN_PREFIX(CryptonightWOW_template_double_end) + +ALIGN(64) +FN_PREFIX(CryptonightWOW_template_part1): + mov QWORD PTR [rsp+16], rbx + mov QWORD PTR [rsp+24], rbp + mov QWORD PTR [rsp+32], rsi + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + push rdi + sub rsp, 64 + mov r12, rcx + mov r8, QWORD PTR [r12+32] + mov rdx, r12 + xor r8, QWORD PTR [r12] + mov r15, QWORD PTR [r12+40] + mov r9, r8 + xor r15, QWORD PTR [r12+8] + mov r11, QWORD PTR [r12+224] + mov r12, QWORD PTR [r12+56] + xor r12, QWORD PTR [rdx+24] + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + movaps XMMWORD PTR [rsp+48], xmm6 + movq xmm0, r12 + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+16], xmm8 + movaps XMMWORD PTR [rsp], xmm9 + mov r12, QWORD PTR [rdx+88] + xor r12, QWORD PTR [rdx+72] + movq xmm6, rax + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm6, xmm0 + and r9d, 2097136 + movq xmm0, r12 + movq xmm7, rax + punpcklqdq xmm7, xmm0 + mov r10d, r9d + movq xmm9, rsp + mov rsp, r8 + mov r8d, 524288 + + mov ebx, [rdx+96] + mov esi, [rdx+100] + mov edi, [rdx+104] + mov ebp, [rdx+108] + + ALIGN(64) +FN_PREFIX(CryptonightWOW_template_mainloop): + movdqa xmm5, XMMWORD PTR [r9+r11] + movq xmm0, r15 + movq xmm4, rsp + punpcklqdq xmm4, xmm0 + lea rdx, QWORD PTR [r9+r11] + + aesenc xmm5, xmm4 + movd r10d, xmm5 + and r10d, 2097136 + + mov r12d, r9d + mov eax, r9d + xor r9d, 48 + xor r12d, 16 + xor eax, 32 + movdqu xmm0, XMMWORD PTR [r9+r11] + movdqu xmm2, XMMWORD PTR [r12+r11] + movdqu xmm1, XMMWORD PTR [rax+r11] + paddq xmm0, xmm7 + paddq xmm2, xmm6 + paddq xmm1, xmm4 + movdqu XMMWORD PTR [r12+r11], xmm0 + movq r12, xmm5 + movdqu XMMWORD PTR [rax+r11], xmm2 + movdqu XMMWORD PTR [r9+r11], xmm1 + + movdqa xmm0, xmm5 + pxor xmm0, xmm6 + movdqu XMMWORD PTR [rdx], xmm0 + + lea r13d, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or r13, rdx + + xor r13, QWORD PTR [r10+r11] + mov r14, QWORD PTR [r10+r11+8] + + movd eax, xmm6 + movd edx, xmm7 + pextrd r9d, xmm7, 2 + +FN_PREFIX(CryptonightWOW_template_part2): + mov rax, r13 + mul r12 + movq xmm0, rax + movq xmm3, rdx + punpcklqdq xmm3, xmm0 + + mov r9d, r10d + mov r12d, r10d + xor r9d, 16 + xor r12d, 32 + xor r10d, 48 + movdqa xmm1, XMMWORD PTR [r12+r11] + xor rdx, QWORD PTR [r12+r11] + xor rax, QWORD PTR [r11+r12+8] + movdqa xmm2, XMMWORD PTR [r9+r11] + pxor xmm3, xmm2 + paddq xmm7, XMMWORD PTR [r10+r11] + paddq xmm1, xmm4 + paddq xmm3, xmm6 + movdqu XMMWORD PTR [r9+r11], xmm7 + movdqu XMMWORD PTR [r12+r11], xmm3 + movdqu XMMWORD PTR [r10+r11], xmm1 + + movdqa xmm7, xmm6 + add r15, rax + add rsp, rdx + xor r10, 48 + mov QWORD PTR [r10+r11], rsp + xor rsp, r13 + mov r9d, esp + mov QWORD PTR [r10+r11+8], r15 + and r9d, 2097136 + xor r15, r14 + movdqa xmm6, xmm5 + dec r8d + jnz FN_PREFIX(CryptonightWOW_template_mainloop) + +FN_PREFIX(CryptonightWOW_template_part3): + movq rsp, xmm9 + + mov rbx, QWORD PTR [rsp+136] + mov rbp, QWORD PTR [rsp+144] + mov rsi, QWORD PTR [rsp+152] + movaps xmm6, XMMWORD PTR [rsp+48] + movaps xmm7, XMMWORD PTR [rsp+32] + movaps xmm8, XMMWORD PTR [rsp+16] + movaps xmm9, XMMWORD PTR [rsp] + add rsp, 64 + pop rdi + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + ret 0 +FN_PREFIX(CryptonightWOW_template_end): + +ALIGN(64) +FN_PREFIX(CryptonightWOW_template_double_part1): + mov QWORD PTR [rsp+24], rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 320 + mov r14, QWORD PTR [rcx+32] + mov r8, rcx + xor r14, QWORD PTR [rcx] + mov r12, QWORD PTR [rcx+40] + mov ebx, r14d + mov rsi, QWORD PTR [rcx+224] + and ebx, 2097136 + xor r12, QWORD PTR [rcx+8] + mov rcx, QWORD PTR [rcx+56] + xor rcx, QWORD PTR [r8+24] + mov rax, QWORD PTR [r8+48] + xor rax, QWORD PTR [r8+16] + mov r15, QWORD PTR [rdx+32] + xor r15, QWORD PTR [rdx] + movq xmm0, rcx + mov rcx, QWORD PTR [r8+88] + xor rcx, QWORD PTR [r8+72] + mov r13, QWORD PTR [rdx+40] + mov rdi, QWORD PTR [rdx+224] + xor r13, QWORD PTR [rdx+8] + movaps XMMWORD PTR [rsp+160], xmm6 + movaps XMMWORD PTR [rsp+176], xmm7 + movaps XMMWORD PTR [rsp+192], xmm8 + movaps XMMWORD PTR [rsp+208], xmm9 + movaps XMMWORD PTR [rsp+224], xmm10 + movaps XMMWORD PTR [rsp+240], xmm11 + movaps XMMWORD PTR [rsp+256], xmm12 + movaps XMMWORD PTR [rsp+272], xmm13 + movaps XMMWORD PTR [rsp+288], xmm14 + movaps XMMWORD PTR [rsp+304], xmm15 + movq xmm7, rax + mov rax, QWORD PTR [r8+80] + xor rax, QWORD PTR [r8+64] + + movaps xmm1, XMMWORD PTR [rdx+96] + movaps xmm2, XMMWORD PTR [r8+96] + movaps XMMWORD PTR [rsp], xmm1 + movaps XMMWORD PTR [rsp+16], xmm2 + + mov r8d, r15d + punpcklqdq xmm7, xmm0 + movq xmm0, rcx + mov rcx, QWORD PTR [rdx+56] + xor rcx, QWORD PTR [rdx+24] + movq xmm9, rax + mov QWORD PTR [rsp+128], rsi + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + punpcklqdq xmm9, xmm0 + movq xmm0, rcx + mov rcx, QWORD PTR [rdx+88] + xor rcx, QWORD PTR [rdx+72] + movq xmm8, rax + mov QWORD PTR [rsp+136], rdi + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm8, xmm0 + and r8d, 2097136 + movq xmm0, rcx + mov r11d, 524288 + movq xmm10, rax + punpcklqdq xmm10, xmm0 + + movq xmm14, QWORD PTR [rsp+128] + movq xmm15, QWORD PTR [rsp+136] + + ALIGN(64) +FN_PREFIX(CryptonightWOW_template_double_mainloop): + movdqu xmm6, XMMWORD PTR [rbx+rsi] + movq xmm0, r12 + mov ecx, ebx + movq xmm3, r14 + punpcklqdq xmm3, xmm0 + xor ebx, 16 + aesenc xmm6, xmm3 + movq rdx, xmm6 + movq xmm4, r15 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + xor ebx, 48 + paddq xmm0, xmm7 + movdqu xmm1, XMMWORD PTR [rbx+rsi] + movdqu XMMWORD PTR [rbx+rsi], xmm0 + paddq xmm1, xmm3 + xor ebx, 16 + mov eax, ebx + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + movdqu XMMWORD PTR [rbx+rsi], xmm1 + paddq xmm0, xmm9 + movdqu XMMWORD PTR [rax+rsi], xmm0 + movdqa xmm0, xmm6 + pxor xmm0, xmm7 + movdqu XMMWORD PTR [rcx+rsi], xmm0 + mov esi, edx + movdqu xmm5, XMMWORD PTR [r8+rdi] + and esi, 2097136 + mov ecx, r8d + movq xmm0, r13 + punpcklqdq xmm4, xmm0 + xor r8d, 16 + aesenc xmm5, xmm4 + movdqu xmm0, XMMWORD PTR [r8+rdi] + xor r8d, 48 + paddq xmm0, xmm8 + movdqu xmm1, XMMWORD PTR [r8+rdi] + movdqu XMMWORD PTR [r8+rdi], xmm0 + paddq xmm1, xmm4 + xor r8d, 16 + mov eax, r8d + xor rax, 32 + movdqu xmm0, XMMWORD PTR [r8+rdi] + movdqu XMMWORD PTR [r8+rdi], xmm1 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rdi], xmm0 + movdqa xmm0, xmm5 + pxor xmm0, xmm8 + movdqu XMMWORD PTR [rcx+rdi], xmm0 + movq rdi, xmm5 + movq rcx, xmm14 + mov ebp, edi + mov r8, QWORD PTR [rcx+rsi] + mov r10, QWORD PTR [rcx+rsi+8] + lea r9, QWORD PTR [rcx+rsi] + xor esi, 16 + + movq xmm0, rsp + movq xmm1, rsi + movq xmm2, rdi + movq xmm11, rbp + movq xmm12, r15 + movq xmm13, rdx + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp+16] + mov esi, DWORD PTR [rsp+20] + mov edi, DWORD PTR [rsp+24] + mov ebp, DWORD PTR [rsp+28] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + xor r8, rax + + movd esp, xmm3 + pextrd r15d, xmm3, 2 + movd eax, xmm7 + movd edx, xmm9 + pextrd r9d, xmm9, 2 + +FN_PREFIX(CryptonightWOW_template_double_part2): + + movq rsp, xmm0 + mov DWORD PTR [rsp+16], ebx + mov DWORD PTR [rsp+20], esi + mov DWORD PTR [rsp+24], edi + mov DWORD PTR [rsp+28], ebp + + movq rsi, xmm1 + movq rdi, xmm2 + movq rbp, xmm11 + movq r15, xmm12 + movq rdx, xmm13 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rbx, r8 + mov rax, r8 + mul rdx + and ebp, 2097136 + mov r8, rax + movq xmm1, rdx + movq xmm0, r8 + punpcklqdq xmm1, xmm0 + pxor xmm1, XMMWORD PTR [rcx+rsi] + xor esi, 48 + paddq xmm1, xmm7 + movdqu xmm2, XMMWORD PTR [rsi+rcx] + xor rdx, QWORD PTR [rsi+rcx] + paddq xmm2, xmm3 + xor r8, QWORD PTR [rsi+rcx+8] + movdqu XMMWORD PTR [rsi+rcx], xmm1 + xor esi, 16 + mov eax, esi + mov rsi, rcx + movdqu xmm0, XMMWORD PTR [rax+rcx] + movdqu XMMWORD PTR [rax+rcx], xmm2 + paddq xmm0, xmm9 + add r12, r8 + xor rax, 32 + add r14, rdx + movdqa xmm9, xmm7 + movdqa xmm7, xmm6 + movdqu XMMWORD PTR [rax+rcx], xmm0 + mov QWORD PTR [r9+8], r12 + xor r12, r10 + mov QWORD PTR [r9], r14 + movq rcx, xmm15 + xor r14, rbx + mov r10d, ebp + mov ebx, r14d + xor ebp, 16 + and ebx, 2097136 + mov r8, QWORD PTR [r10+rcx] + mov r9, QWORD PTR [r10+rcx+8] + + movq xmm0, rsp + movq xmm1, rbx + movq xmm2, rsi + movq xmm11, rdi + movq xmm12, rbp + movq xmm13, r15 + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp] + mov esi, DWORD PTR [rsp+4] + mov edi, DWORD PTR [rsp+8] + mov ebp, DWORD PTR [rsp+12] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + + xor r8, rax + movq xmm3, r8 + + movd esp, xmm4 + pextrd r15d, xmm4, 2 + movd eax, xmm8 + movd edx, xmm10 + pextrd r9d, xmm10, 2 + +FN_PREFIX(CryptonightWOW_template_double_part3): + + movq rsp, xmm0 + mov DWORD PTR [rsp], ebx + mov DWORD PTR [rsp+4], esi + mov DWORD PTR [rsp+8], edi + mov DWORD PTR [rsp+12], ebp + + movq rbx, xmm1 + movq rsi, xmm2 + movq rdi, xmm11 + movq rbp, xmm12 + movq r15, xmm13 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rax, r8 + mul rdi + movq xmm1, rdx + movq xmm0, rax + punpcklqdq xmm1, xmm0 + mov rdi, rcx + mov r8, rax + pxor xmm1, XMMWORD PTR [rbp+rcx] + xor ebp, 48 + paddq xmm1, xmm8 + xor r8, QWORD PTR [rbp+rcx+8] + xor rdx, QWORD PTR [rbp+rcx] + add r13, r8 + movdqu xmm2, XMMWORD PTR [rbp+rcx] + add r15, rdx + movdqu XMMWORD PTR [rbp+rcx], xmm1 + paddq xmm2, xmm4 + xor ebp, 16 + mov eax, ebp + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbp+rcx] + movdqu XMMWORD PTR [rbp+rcx], xmm2 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rcx], xmm0 + movq rax, xmm3 + movdqa xmm10, xmm8 + mov QWORD PTR [r10+rcx], r15 + movdqa xmm8, xmm5 + xor r15, rax + mov QWORD PTR [r10+rcx+8], r13 + mov r8d, r15d + xor r13, r9 + and r8d, 2097136 + dec r11d + jnz FN_PREFIX(CryptonightWOW_template_double_mainloop) + +FN_PREFIX(CryptonightWOW_template_double_part4): + + mov rbx, QWORD PTR [rsp+400] + movaps xmm6, XMMWORD PTR [rsp+160] + movaps xmm7, XMMWORD PTR [rsp+176] + movaps xmm8, XMMWORD PTR [rsp+192] + movaps xmm9, XMMWORD PTR [rsp+208] + movaps xmm10, XMMWORD PTR [rsp+224] + movaps xmm11, XMMWORD PTR [rsp+240] + movaps xmm12, XMMWORD PTR [rsp+256] + movaps xmm13, XMMWORD PTR [rsp+272] + movaps xmm14, XMMWORD PTR [rsp+288] + movaps xmm15, XMMWORD PTR [rsp+304] + add rsp, 320 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + ret 0 +FN_PREFIX(CryptonightWOW_template_double_end): diff --git a/src/Native/libcryptonight/crypto/asm/cnv2_double_main_loop_sandybridge.inc b/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_double_main_loop_sandybridge.inc similarity index 99% rename from src/Native/libcryptonight/crypto/asm/cnv2_double_main_loop_sandybridge.inc rename to src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_double_main_loop_sandybridge.inc index e8251bc7f..aa5101a83 100644 --- a/src/Native/libcryptonight/crypto/asm/cnv2_double_main_loop_sandybridge.inc +++ b/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_double_main_loop_sandybridge.inc @@ -94,7 +94,7 @@ lea r9, QWORD PTR [rdx+r13] movdqu xmm15, XMMWORD PTR [r9] - ALIGN 16 + ALIGN(64) main_loop_double_sandybridge: movdqu xmm9, xmm15 mov eax, edx diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_main_loop_bulldozer.inc b/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_main_loop_bulldozer.inc new file mode 100644 index 000000000..c764501db --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_main_loop_bulldozer.inc @@ -0,0 +1,180 @@ + mov QWORD PTR [rsp+16], rbx + mov QWORD PTR [rsp+24], rbp + mov QWORD PTR [rsp+32], rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 64 + + stmxcsr DWORD PTR [rsp] + mov DWORD PTR [rsp+4], 24448 + ldmxcsr DWORD PTR [rsp+4] + + mov rax, QWORD PTR [rcx+48] + mov r9, rcx + xor rax, QWORD PTR [rcx+16] + mov ebp, 524288 + mov r8, QWORD PTR [rcx+32] + xor r8, QWORD PTR [rcx] + mov r11, QWORD PTR [rcx+40] + mov r10, r8 + mov rdx, QWORD PTR [rcx+56] + movq xmm3, rax + xor rdx, QWORD PTR [rcx+24] + xor r11, QWORD PTR [rcx+8] + mov rbx, QWORD PTR [rcx+224] + mov rax, QWORD PTR [r9+80] + xor rax, QWORD PTR [r9+64] + movq xmm0, rdx + mov rcx, QWORD PTR [rcx+88] + xor rcx, QWORD PTR [r9+72] + mov rdi, QWORD PTR [r9+104] + and r10d, 2097136 + movaps XMMWORD PTR [rsp+48], xmm6 + movq xmm4, rax + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+16], xmm8 + xorps xmm8, xmm8 + mov ax, 1023 + shl rax, 52 + movq xmm7, rax + mov r15, QWORD PTR [r9+96] + punpcklqdq xmm3, xmm0 + movq xmm0, rcx + punpcklqdq xmm4, xmm0 + + ALIGN(64) +cnv2_main_loop_bulldozer: + movdqa xmm5, XMMWORD PTR [r10+rbx] + movq xmm6, r8 + pinsrq xmm6, r11, 1 + lea rdx, QWORD PTR [r10+rbx] + lea r9, QWORD PTR [rdi+rdi] + shl rdi, 32 + + mov ecx, r10d + mov eax, r10d + xor ecx, 16 + xor eax, 32 + xor r10d, 48 + aesenc xmm5, xmm6 + movdqa xmm2, XMMWORD PTR [rcx+rbx] + movdqa xmm1, XMMWORD PTR [rax+rbx] + movdqa xmm0, XMMWORD PTR [r10+rbx] + paddq xmm2, xmm3 + paddq xmm1, xmm6 + paddq xmm0, xmm4 + movdqa XMMWORD PTR [rcx+rbx], xmm0 + movdqa XMMWORD PTR [rax+rbx], xmm2 + movdqa XMMWORD PTR [r10+rbx], xmm1 + + movaps xmm1, xmm8 + mov rsi, r15 + xor rsi, rdi + + mov edi, 1023 + shl rdi, 52 + + movq r14, xmm5 + pextrq rax, xmm5, 1 + + movdqa xmm0, xmm5 + pxor xmm0, xmm3 + mov r10, r14 + and r10d, 2097136 + movdqa XMMWORD PTR [rdx], xmm0 + xor rsi, QWORD PTR [r10+rbx] + lea r12, QWORD PTR [r10+rbx] + mov r13, QWORD PTR [r10+rbx+8] + + add r9d, r14d + or r9d, -2147483647 + xor edx, edx + div r9 + mov eax, eax + shl rdx, 32 + lea r15, [rax+rdx] + lea rax, [r14+r15] + shr rax, 12 + add rax, rdi + movq xmm0, rax + sqrtsd xmm1, xmm0 + movq rdi, xmm1 + test rdi, 524287 + je sqrt_fixup_bulldozer + shr rdi, 19 + +sqrt_fixup_bulldozer_ret: + mov rax, rsi + mul r14 + movq xmm1, rax + movq xmm0, rdx + punpcklqdq xmm0, xmm1 + + mov r9d, r10d + mov ecx, r10d + xor r9d, 16 + xor ecx, 32 + xor r10d, 48 + movdqa xmm1, XMMWORD PTR [rcx+rbx] + xor rdx, [rcx+rbx] + xor rax, [rcx+rbx+8] + movdqa xmm2, XMMWORD PTR [r9+rbx] + pxor xmm2, xmm0 + paddq xmm4, XMMWORD PTR [r10+rbx] + paddq xmm2, xmm3 + paddq xmm1, xmm6 + movdqa XMMWORD PTR [r9+rbx], xmm4 + movdqa XMMWORD PTR [rcx+rbx], xmm2 + movdqa XMMWORD PTR [r10+rbx], xmm1 + + movdqa xmm4, xmm3 + add r8, rdx + add r11, rax + mov QWORD PTR [r12], r8 + xor r8, rsi + mov QWORD PTR [r12+8], r11 + mov r10, r8 + xor r11, r13 + and r10d, 2097136 + movdqa xmm3, xmm5 + dec ebp + jne cnv2_main_loop_bulldozer + + ldmxcsr DWORD PTR [rsp] + movaps xmm6, XMMWORD PTR [rsp+48] + lea r11, QWORD PTR [rsp+64] + mov rbx, QWORD PTR [r11+56] + mov rbp, QWORD PTR [r11+64] + mov rsi, QWORD PTR [r11+72] + movaps xmm8, XMMWORD PTR [r11-48] + movaps xmm7, XMMWORD PTR [rsp+32] + mov rsp, r11 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + jmp cnv2_main_loop_bulldozer_endp + +sqrt_fixup_bulldozer: + movq r9, xmm5 + add r9, r15 + dec rdi + mov edx, -1022 + shl rdx, 32 + mov rax, rdi + shr rdi, 19 + shr rax, 20 + mov rcx, rdi + sub rcx, rax + lea rcx, [rcx+rdx+1] + add rax, rdx + imul rcx, rax + sub rcx, r9 + adc rdi, 0 + jmp sqrt_fixup_bulldozer_ret + +cnv2_main_loop_bulldozer_endp: diff --git a/src/Native/libcryptonight/crypto/asm/cnv2_main_loop_ivybridge.inc b/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_main_loop_ivybridge.inc similarity index 99% rename from src/Native/libcryptonight/crypto/asm/cnv2_main_loop_ivybridge.inc rename to src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_main_loop_ivybridge.inc index 8c2c2d3b0..06f1d28be 100644 --- a/src/Native/libcryptonight/crypto/asm/cnv2_main_loop_ivybridge.inc +++ b/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_main_loop_ivybridge.inc @@ -50,7 +50,7 @@ punpcklqdq xmm5, xmm0 movdqu xmm6, XMMWORD PTR [r10+rbx] - ALIGN 16 + ALIGN(64) main_loop_ivybridge: lea rdx, QWORD PTR [r10+rbx] mov ecx, r10d diff --git a/src/Native/libcryptonight/crypto/asm/cnv2_main_loop_ryzen.inc b/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_main_loop_ryzen.inc similarity index 99% rename from src/Native/libcryptonight/crypto/asm/cnv2_main_loop_ryzen.inc rename to src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_main_loop_ryzen.inc index d386aa2df..5dbf5917f 100644 --- a/src/Native/libcryptonight/crypto/asm/cnv2_main_loop_ryzen.inc +++ b/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_main_loop_ryzen.inc @@ -45,7 +45,7 @@ movq xmm0, rcx punpcklqdq xmm4, xmm0 - ALIGN 16 + ALIGN(64) main_loop_ryzen: movdqa xmm5, XMMWORD PTR [r10+rbx] movq xmm0, r11 diff --git a/src/Native/libcryptonight/crypto/asm/cnv2_main_loop.S b/src/Native/libcryptonight/xmrig/crypto/asm/cn_main_loop.S similarity index 51% rename from src/Native/libcryptonight/crypto/asm/cnv2_main_loop.S rename to src/Native/libcryptonight/xmrig/crypto/asm/cn_main_loop.S index 4dbcbbda7..a792337f0 100644 --- a/src/Native/libcryptonight/crypto/asm/cnv2_main_loop.S +++ b/src/Native/libcryptonight/xmrig/crypto/asm/cn_main_loop.S @@ -1,4 +1,8 @@ -#define ALIGN .align +#ifdef __APPLE__ +# define ALIGN(x) .align 6 +#else +# define ALIGN(x) .align 64 +#endif .intel_syntax noprefix #ifdef __APPLE__ # define FN_PREFIX(fn) _ ## fn @@ -9,29 +13,42 @@ #endif .global FN_PREFIX(cnv2_mainloop_ivybridge_asm) .global FN_PREFIX(cnv2_mainloop_ryzen_asm) +.global FN_PREFIX(cnv2_mainloop_bulldozer_asm) .global FN_PREFIX(cnv2_double_mainloop_sandybridge_asm) -ALIGN 16 +ALIGN(64) FN_PREFIX(cnv2_mainloop_ivybridge_asm): sub rsp, 48 mov rcx, rdi - #include "cnv2_main_loop_ivybridge.inc" + #include "cn2/cnv2_main_loop_ivybridge.inc" add rsp, 48 ret 0 + mov eax, 3735929054 -ALIGN 16 +ALIGN(64) FN_PREFIX(cnv2_mainloop_ryzen_asm): sub rsp, 48 mov rcx, rdi - #include "cnv2_main_loop_ryzen.inc" + #include "cn2/cnv2_main_loop_ryzen.inc" + add rsp, 48 + ret 0 + mov eax, 3735929054 + +ALIGN(64) +FN_PREFIX(cnv2_mainloop_bulldozer_asm): + sub rsp, 48 + mov rcx, rdi + #include "cn2/cnv2_main_loop_bulldozer.inc" add rsp, 48 ret 0 + mov eax, 3735929054 -ALIGN 16 +ALIGN(64) FN_PREFIX(cnv2_double_mainloop_sandybridge_asm): sub rsp, 48 mov rcx, rdi mov rdx, rsi - #include "cnv2_double_main_loop_sandybridge.inc" + #include "cn2/cnv2_double_main_loop_sandybridge.inc" add rsp, 48 ret 0 + mov eax, 3735929054 diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.S b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.S new file mode 100644 index 000000000..5f3046cb9 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.S @@ -0,0 +1,1593 @@ +#ifdef __APPLE__ +# define ALIGN(x) .align 6 +#else +# define ALIGN(x) .align 64 +#endif +.intel_syntax noprefix +#ifdef __APPLE__ +# define FN_PREFIX(fn) _ ## fn +.text +#else +# define FN_PREFIX(fn) fn +.section .text +#endif + +#define PUBLIC .global + +PUBLIC FN_PREFIX(CryptonightR_instruction0) +PUBLIC FN_PREFIX(CryptonightR_instruction1) +PUBLIC FN_PREFIX(CryptonightR_instruction2) +PUBLIC FN_PREFIX(CryptonightR_instruction3) +PUBLIC FN_PREFIX(CryptonightR_instruction4) +PUBLIC FN_PREFIX(CryptonightR_instruction5) +PUBLIC FN_PREFIX(CryptonightR_instruction6) +PUBLIC FN_PREFIX(CryptonightR_instruction7) +PUBLIC FN_PREFIX(CryptonightR_instruction8) +PUBLIC FN_PREFIX(CryptonightR_instruction9) +PUBLIC FN_PREFIX(CryptonightR_instruction10) +PUBLIC FN_PREFIX(CryptonightR_instruction11) +PUBLIC FN_PREFIX(CryptonightR_instruction12) +PUBLIC FN_PREFIX(CryptonightR_instruction13) +PUBLIC FN_PREFIX(CryptonightR_instruction14) +PUBLIC FN_PREFIX(CryptonightR_instruction15) +PUBLIC FN_PREFIX(CryptonightR_instruction16) +PUBLIC FN_PREFIX(CryptonightR_instruction17) +PUBLIC FN_PREFIX(CryptonightR_instruction18) +PUBLIC FN_PREFIX(CryptonightR_instruction19) +PUBLIC FN_PREFIX(CryptonightR_instruction20) +PUBLIC FN_PREFIX(CryptonightR_instruction21) +PUBLIC FN_PREFIX(CryptonightR_instruction22) +PUBLIC FN_PREFIX(CryptonightR_instruction23) +PUBLIC FN_PREFIX(CryptonightR_instruction24) +PUBLIC FN_PREFIX(CryptonightR_instruction25) +PUBLIC FN_PREFIX(CryptonightR_instruction26) +PUBLIC FN_PREFIX(CryptonightR_instruction27) +PUBLIC FN_PREFIX(CryptonightR_instruction28) +PUBLIC FN_PREFIX(CryptonightR_instruction29) +PUBLIC FN_PREFIX(CryptonightR_instruction30) +PUBLIC FN_PREFIX(CryptonightR_instruction31) +PUBLIC FN_PREFIX(CryptonightR_instruction32) +PUBLIC FN_PREFIX(CryptonightR_instruction33) +PUBLIC FN_PREFIX(CryptonightR_instruction34) +PUBLIC FN_PREFIX(CryptonightR_instruction35) +PUBLIC FN_PREFIX(CryptonightR_instruction36) +PUBLIC FN_PREFIX(CryptonightR_instruction37) +PUBLIC FN_PREFIX(CryptonightR_instruction38) +PUBLIC FN_PREFIX(CryptonightR_instruction39) +PUBLIC FN_PREFIX(CryptonightR_instruction40) +PUBLIC FN_PREFIX(CryptonightR_instruction41) +PUBLIC FN_PREFIX(CryptonightR_instruction42) +PUBLIC FN_PREFIX(CryptonightR_instruction43) +PUBLIC FN_PREFIX(CryptonightR_instruction44) +PUBLIC FN_PREFIX(CryptonightR_instruction45) +PUBLIC FN_PREFIX(CryptonightR_instruction46) +PUBLIC FN_PREFIX(CryptonightR_instruction47) +PUBLIC FN_PREFIX(CryptonightR_instruction48) +PUBLIC FN_PREFIX(CryptonightR_instruction49) +PUBLIC FN_PREFIX(CryptonightR_instruction50) +PUBLIC FN_PREFIX(CryptonightR_instruction51) +PUBLIC FN_PREFIX(CryptonightR_instruction52) +PUBLIC FN_PREFIX(CryptonightR_instruction53) +PUBLIC FN_PREFIX(CryptonightR_instruction54) +PUBLIC FN_PREFIX(CryptonightR_instruction55) +PUBLIC FN_PREFIX(CryptonightR_instruction56) +PUBLIC FN_PREFIX(CryptonightR_instruction57) +PUBLIC FN_PREFIX(CryptonightR_instruction58) +PUBLIC FN_PREFIX(CryptonightR_instruction59) +PUBLIC FN_PREFIX(CryptonightR_instruction60) +PUBLIC FN_PREFIX(CryptonightR_instruction61) +PUBLIC FN_PREFIX(CryptonightR_instruction62) +PUBLIC FN_PREFIX(CryptonightR_instruction63) +PUBLIC FN_PREFIX(CryptonightR_instruction64) +PUBLIC FN_PREFIX(CryptonightR_instruction65) +PUBLIC FN_PREFIX(CryptonightR_instruction66) +PUBLIC FN_PREFIX(CryptonightR_instruction67) +PUBLIC FN_PREFIX(CryptonightR_instruction68) +PUBLIC FN_PREFIX(CryptonightR_instruction69) +PUBLIC FN_PREFIX(CryptonightR_instruction70) +PUBLIC FN_PREFIX(CryptonightR_instruction71) +PUBLIC FN_PREFIX(CryptonightR_instruction72) +PUBLIC FN_PREFIX(CryptonightR_instruction73) +PUBLIC FN_PREFIX(CryptonightR_instruction74) +PUBLIC FN_PREFIX(CryptonightR_instruction75) +PUBLIC FN_PREFIX(CryptonightR_instruction76) +PUBLIC FN_PREFIX(CryptonightR_instruction77) +PUBLIC FN_PREFIX(CryptonightR_instruction78) +PUBLIC FN_PREFIX(CryptonightR_instruction79) +PUBLIC FN_PREFIX(CryptonightR_instruction80) +PUBLIC FN_PREFIX(CryptonightR_instruction81) +PUBLIC FN_PREFIX(CryptonightR_instruction82) +PUBLIC FN_PREFIX(CryptonightR_instruction83) +PUBLIC FN_PREFIX(CryptonightR_instruction84) +PUBLIC FN_PREFIX(CryptonightR_instruction85) +PUBLIC FN_PREFIX(CryptonightR_instruction86) +PUBLIC FN_PREFIX(CryptonightR_instruction87) +PUBLIC FN_PREFIX(CryptonightR_instruction88) +PUBLIC FN_PREFIX(CryptonightR_instruction89) +PUBLIC FN_PREFIX(CryptonightR_instruction90) +PUBLIC FN_PREFIX(CryptonightR_instruction91) +PUBLIC FN_PREFIX(CryptonightR_instruction92) +PUBLIC FN_PREFIX(CryptonightR_instruction93) +PUBLIC FN_PREFIX(CryptonightR_instruction94) +PUBLIC FN_PREFIX(CryptonightR_instruction95) +PUBLIC FN_PREFIX(CryptonightR_instruction96) +PUBLIC FN_PREFIX(CryptonightR_instruction97) +PUBLIC FN_PREFIX(CryptonightR_instruction98) +PUBLIC FN_PREFIX(CryptonightR_instruction99) +PUBLIC FN_PREFIX(CryptonightR_instruction100) +PUBLIC FN_PREFIX(CryptonightR_instruction101) +PUBLIC FN_PREFIX(CryptonightR_instruction102) +PUBLIC FN_PREFIX(CryptonightR_instruction103) +PUBLIC FN_PREFIX(CryptonightR_instruction104) +PUBLIC FN_PREFIX(CryptonightR_instruction105) +PUBLIC FN_PREFIX(CryptonightR_instruction106) +PUBLIC FN_PREFIX(CryptonightR_instruction107) +PUBLIC FN_PREFIX(CryptonightR_instruction108) +PUBLIC FN_PREFIX(CryptonightR_instruction109) +PUBLIC FN_PREFIX(CryptonightR_instruction110) +PUBLIC FN_PREFIX(CryptonightR_instruction111) +PUBLIC FN_PREFIX(CryptonightR_instruction112) +PUBLIC FN_PREFIX(CryptonightR_instruction113) +PUBLIC FN_PREFIX(CryptonightR_instruction114) +PUBLIC FN_PREFIX(CryptonightR_instruction115) +PUBLIC FN_PREFIX(CryptonightR_instruction116) +PUBLIC FN_PREFIX(CryptonightR_instruction117) +PUBLIC FN_PREFIX(CryptonightR_instruction118) +PUBLIC FN_PREFIX(CryptonightR_instruction119) +PUBLIC FN_PREFIX(CryptonightR_instruction120) +PUBLIC FN_PREFIX(CryptonightR_instruction121) +PUBLIC FN_PREFIX(CryptonightR_instruction122) +PUBLIC FN_PREFIX(CryptonightR_instruction123) +PUBLIC FN_PREFIX(CryptonightR_instruction124) +PUBLIC FN_PREFIX(CryptonightR_instruction125) +PUBLIC FN_PREFIX(CryptonightR_instruction126) +PUBLIC FN_PREFIX(CryptonightR_instruction127) +PUBLIC FN_PREFIX(CryptonightR_instruction128) +PUBLIC FN_PREFIX(CryptonightR_instruction129) +PUBLIC FN_PREFIX(CryptonightR_instruction130) +PUBLIC FN_PREFIX(CryptonightR_instruction131) +PUBLIC FN_PREFIX(CryptonightR_instruction132) +PUBLIC FN_PREFIX(CryptonightR_instruction133) +PUBLIC FN_PREFIX(CryptonightR_instruction134) +PUBLIC FN_PREFIX(CryptonightR_instruction135) +PUBLIC FN_PREFIX(CryptonightR_instruction136) +PUBLIC FN_PREFIX(CryptonightR_instruction137) +PUBLIC FN_PREFIX(CryptonightR_instruction138) +PUBLIC FN_PREFIX(CryptonightR_instruction139) +PUBLIC FN_PREFIX(CryptonightR_instruction140) +PUBLIC FN_PREFIX(CryptonightR_instruction141) +PUBLIC FN_PREFIX(CryptonightR_instruction142) +PUBLIC FN_PREFIX(CryptonightR_instruction143) +PUBLIC FN_PREFIX(CryptonightR_instruction144) +PUBLIC FN_PREFIX(CryptonightR_instruction145) +PUBLIC FN_PREFIX(CryptonightR_instruction146) +PUBLIC FN_PREFIX(CryptonightR_instruction147) +PUBLIC FN_PREFIX(CryptonightR_instruction148) +PUBLIC FN_PREFIX(CryptonightR_instruction149) +PUBLIC FN_PREFIX(CryptonightR_instruction150) +PUBLIC FN_PREFIX(CryptonightR_instruction151) +PUBLIC FN_PREFIX(CryptonightR_instruction152) +PUBLIC FN_PREFIX(CryptonightR_instruction153) +PUBLIC FN_PREFIX(CryptonightR_instruction154) +PUBLIC FN_PREFIX(CryptonightR_instruction155) +PUBLIC FN_PREFIX(CryptonightR_instruction156) +PUBLIC FN_PREFIX(CryptonightR_instruction157) +PUBLIC FN_PREFIX(CryptonightR_instruction158) +PUBLIC FN_PREFIX(CryptonightR_instruction159) +PUBLIC FN_PREFIX(CryptonightR_instruction160) +PUBLIC FN_PREFIX(CryptonightR_instruction161) +PUBLIC FN_PREFIX(CryptonightR_instruction162) +PUBLIC FN_PREFIX(CryptonightR_instruction163) +PUBLIC FN_PREFIX(CryptonightR_instruction164) +PUBLIC FN_PREFIX(CryptonightR_instruction165) +PUBLIC FN_PREFIX(CryptonightR_instruction166) +PUBLIC FN_PREFIX(CryptonightR_instruction167) +PUBLIC FN_PREFIX(CryptonightR_instruction168) +PUBLIC FN_PREFIX(CryptonightR_instruction169) +PUBLIC FN_PREFIX(CryptonightR_instruction170) +PUBLIC FN_PREFIX(CryptonightR_instruction171) +PUBLIC FN_PREFIX(CryptonightR_instruction172) +PUBLIC FN_PREFIX(CryptonightR_instruction173) +PUBLIC FN_PREFIX(CryptonightR_instruction174) +PUBLIC FN_PREFIX(CryptonightR_instruction175) +PUBLIC FN_PREFIX(CryptonightR_instruction176) +PUBLIC FN_PREFIX(CryptonightR_instruction177) +PUBLIC FN_PREFIX(CryptonightR_instruction178) +PUBLIC FN_PREFIX(CryptonightR_instruction179) +PUBLIC FN_PREFIX(CryptonightR_instruction180) +PUBLIC FN_PREFIX(CryptonightR_instruction181) +PUBLIC FN_PREFIX(CryptonightR_instruction182) +PUBLIC FN_PREFIX(CryptonightR_instruction183) +PUBLIC FN_PREFIX(CryptonightR_instruction184) +PUBLIC FN_PREFIX(CryptonightR_instruction185) +PUBLIC FN_PREFIX(CryptonightR_instruction186) +PUBLIC FN_PREFIX(CryptonightR_instruction187) +PUBLIC FN_PREFIX(CryptonightR_instruction188) +PUBLIC FN_PREFIX(CryptonightR_instruction189) +PUBLIC FN_PREFIX(CryptonightR_instruction190) +PUBLIC FN_PREFIX(CryptonightR_instruction191) +PUBLIC FN_PREFIX(CryptonightR_instruction192) +PUBLIC FN_PREFIX(CryptonightR_instruction193) +PUBLIC FN_PREFIX(CryptonightR_instruction194) +PUBLIC FN_PREFIX(CryptonightR_instruction195) +PUBLIC FN_PREFIX(CryptonightR_instruction196) +PUBLIC FN_PREFIX(CryptonightR_instruction197) +PUBLIC FN_PREFIX(CryptonightR_instruction198) +PUBLIC FN_PREFIX(CryptonightR_instruction199) +PUBLIC FN_PREFIX(CryptonightR_instruction200) +PUBLIC FN_PREFIX(CryptonightR_instruction201) +PUBLIC FN_PREFIX(CryptonightR_instruction202) +PUBLIC FN_PREFIX(CryptonightR_instruction203) +PUBLIC FN_PREFIX(CryptonightR_instruction204) +PUBLIC FN_PREFIX(CryptonightR_instruction205) +PUBLIC FN_PREFIX(CryptonightR_instruction206) +PUBLIC FN_PREFIX(CryptonightR_instruction207) +PUBLIC FN_PREFIX(CryptonightR_instruction208) +PUBLIC FN_PREFIX(CryptonightR_instruction209) +PUBLIC FN_PREFIX(CryptonightR_instruction210) +PUBLIC FN_PREFIX(CryptonightR_instruction211) +PUBLIC FN_PREFIX(CryptonightR_instruction212) +PUBLIC FN_PREFIX(CryptonightR_instruction213) +PUBLIC FN_PREFIX(CryptonightR_instruction214) +PUBLIC FN_PREFIX(CryptonightR_instruction215) +PUBLIC FN_PREFIX(CryptonightR_instruction216) +PUBLIC FN_PREFIX(CryptonightR_instruction217) +PUBLIC FN_PREFIX(CryptonightR_instruction218) +PUBLIC FN_PREFIX(CryptonightR_instruction219) +PUBLIC FN_PREFIX(CryptonightR_instruction220) +PUBLIC FN_PREFIX(CryptonightR_instruction221) +PUBLIC FN_PREFIX(CryptonightR_instruction222) +PUBLIC FN_PREFIX(CryptonightR_instruction223) +PUBLIC FN_PREFIX(CryptonightR_instruction224) +PUBLIC FN_PREFIX(CryptonightR_instruction225) +PUBLIC FN_PREFIX(CryptonightR_instruction226) +PUBLIC FN_PREFIX(CryptonightR_instruction227) +PUBLIC FN_PREFIX(CryptonightR_instruction228) +PUBLIC FN_PREFIX(CryptonightR_instruction229) +PUBLIC FN_PREFIX(CryptonightR_instruction230) +PUBLIC FN_PREFIX(CryptonightR_instruction231) +PUBLIC FN_PREFIX(CryptonightR_instruction232) +PUBLIC FN_PREFIX(CryptonightR_instruction233) +PUBLIC FN_PREFIX(CryptonightR_instruction234) +PUBLIC FN_PREFIX(CryptonightR_instruction235) +PUBLIC FN_PREFIX(CryptonightR_instruction236) +PUBLIC FN_PREFIX(CryptonightR_instruction237) +PUBLIC FN_PREFIX(CryptonightR_instruction238) +PUBLIC FN_PREFIX(CryptonightR_instruction239) +PUBLIC FN_PREFIX(CryptonightR_instruction240) +PUBLIC FN_PREFIX(CryptonightR_instruction241) +PUBLIC FN_PREFIX(CryptonightR_instruction242) +PUBLIC FN_PREFIX(CryptonightR_instruction243) +PUBLIC FN_PREFIX(CryptonightR_instruction244) +PUBLIC FN_PREFIX(CryptonightR_instruction245) +PUBLIC FN_PREFIX(CryptonightR_instruction246) +PUBLIC FN_PREFIX(CryptonightR_instruction247) +PUBLIC FN_PREFIX(CryptonightR_instruction248) +PUBLIC FN_PREFIX(CryptonightR_instruction249) +PUBLIC FN_PREFIX(CryptonightR_instruction250) +PUBLIC FN_PREFIX(CryptonightR_instruction251) +PUBLIC FN_PREFIX(CryptonightR_instruction252) +PUBLIC FN_PREFIX(CryptonightR_instruction253) +PUBLIC FN_PREFIX(CryptonightR_instruction254) +PUBLIC FN_PREFIX(CryptonightR_instruction255) +PUBLIC FN_PREFIX(CryptonightR_instruction256) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov0) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov1) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov2) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov3) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov4) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov5) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov6) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov7) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov8) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov9) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov10) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov11) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov12) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov13) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov14) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov15) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov16) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov17) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov18) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov19) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov20) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov21) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov22) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov23) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov24) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov25) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov26) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov27) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov28) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov29) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov30) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov31) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov32) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov33) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov34) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov35) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov36) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov37) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov38) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov39) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov40) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov41) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov42) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov43) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov44) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov45) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov46) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov47) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov48) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov49) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov50) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov51) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov52) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov53) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov54) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov55) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov56) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov57) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov58) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov59) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov60) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov61) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov62) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov63) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov64) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov65) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov66) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov67) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov68) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov69) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov70) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov71) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov72) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov73) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov74) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov75) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov76) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov77) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov78) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov79) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov80) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov81) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov82) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov83) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov84) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov85) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov86) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov87) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov88) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov89) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov90) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov91) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov92) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov93) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov94) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov95) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov96) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov97) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov98) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov99) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov100) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov101) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov102) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov103) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov104) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov105) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov106) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov107) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov108) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov109) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov110) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov111) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov112) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov113) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov114) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov115) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov116) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov117) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov118) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov119) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov120) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov121) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov122) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov123) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov124) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov125) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov126) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov127) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov128) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov129) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov130) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov131) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov132) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov133) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov134) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov135) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov136) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov137) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov138) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov139) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov140) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov141) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov142) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov143) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov144) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov145) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov146) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov147) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov148) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov149) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov150) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov151) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov152) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov153) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov154) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov155) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov156) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov157) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov158) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov159) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov160) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov161) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov162) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov163) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov164) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov165) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov166) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov167) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov168) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov169) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov170) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov171) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov172) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov173) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov174) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov175) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov176) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov177) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov178) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov179) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov180) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov181) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov182) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov183) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov184) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov185) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov186) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov187) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov188) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov189) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov190) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov191) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov192) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov193) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov194) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov195) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov196) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov197) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov198) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov199) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov200) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov201) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov202) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov203) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov204) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov205) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov206) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov207) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov208) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov209) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov210) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov211) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov212) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov213) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov214) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov215) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov216) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov217) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov218) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov219) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov220) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov221) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov222) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov223) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov224) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov225) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov226) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov227) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov228) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov229) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov230) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov231) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov232) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov233) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov234) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov235) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov236) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov237) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov238) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov239) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov240) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov241) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov242) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov243) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov244) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov245) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov246) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov247) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov248) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov249) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov250) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov251) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov252) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov253) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov254) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov255) +PUBLIC FN_PREFIX(CryptonightR_instruction_mov256) + +#include "CryptonightWOW_template.inc" +#include "CryptonightR_template.inc" + +FN_PREFIX(CryptonightR_instruction0): + imul rbx, rbx +FN_PREFIX(CryptonightR_instruction1): + imul rbx, rbx +FN_PREFIX(CryptonightR_instruction2): + imul rbx, rbx +FN_PREFIX(CryptonightR_instruction3): + add rbx, r9 + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction4): + sub rbx, r9 +FN_PREFIX(CryptonightR_instruction5): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction6): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction7): + xor rbx, r9 +FN_PREFIX(CryptonightR_instruction8): + imul rsi, rbx +FN_PREFIX(CryptonightR_instruction9): + imul rsi, rbx +FN_PREFIX(CryptonightR_instruction10): + imul rsi, rbx +FN_PREFIX(CryptonightR_instruction11): + add rsi, rbx + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction12): + sub rsi, rbx +FN_PREFIX(CryptonightR_instruction13): + ror esi, cl +FN_PREFIX(CryptonightR_instruction14): + rol esi, cl +FN_PREFIX(CryptonightR_instruction15): + xor rsi, rbx +FN_PREFIX(CryptonightR_instruction16): + imul rdi, rbx +FN_PREFIX(CryptonightR_instruction17): + imul rdi, rbx +FN_PREFIX(CryptonightR_instruction18): + imul rdi, rbx +FN_PREFIX(CryptonightR_instruction19): + add rdi, rbx + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction20): + sub rdi, rbx +FN_PREFIX(CryptonightR_instruction21): + ror edi, cl +FN_PREFIX(CryptonightR_instruction22): + rol edi, cl +FN_PREFIX(CryptonightR_instruction23): + xor rdi, rbx +FN_PREFIX(CryptonightR_instruction24): + imul rbp, rbx +FN_PREFIX(CryptonightR_instruction25): + imul rbp, rbx +FN_PREFIX(CryptonightR_instruction26): + imul rbp, rbx +FN_PREFIX(CryptonightR_instruction27): + add rbp, rbx + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction28): + sub rbp, rbx +FN_PREFIX(CryptonightR_instruction29): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction30): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction31): + xor rbp, rbx +FN_PREFIX(CryptonightR_instruction32): + imul rbx, rsi +FN_PREFIX(CryptonightR_instruction33): + imul rbx, rsi +FN_PREFIX(CryptonightR_instruction34): + imul rbx, rsi +FN_PREFIX(CryptonightR_instruction35): + add rbx, rsi + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction36): + sub rbx, rsi +FN_PREFIX(CryptonightR_instruction37): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction38): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction39): + xor rbx, rsi +FN_PREFIX(CryptonightR_instruction40): + imul rsi, rsi +FN_PREFIX(CryptonightR_instruction41): + imul rsi, rsi +FN_PREFIX(CryptonightR_instruction42): + imul rsi, rsi +FN_PREFIX(CryptonightR_instruction43): + add rsi, r9 + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction44): + sub rsi, r9 +FN_PREFIX(CryptonightR_instruction45): + ror esi, cl +FN_PREFIX(CryptonightR_instruction46): + rol esi, cl +FN_PREFIX(CryptonightR_instruction47): + xor rsi, r9 +FN_PREFIX(CryptonightR_instruction48): + imul rdi, rsi +FN_PREFIX(CryptonightR_instruction49): + imul rdi, rsi +FN_PREFIX(CryptonightR_instruction50): + imul rdi, rsi +FN_PREFIX(CryptonightR_instruction51): + add rdi, rsi + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction52): + sub rdi, rsi +FN_PREFIX(CryptonightR_instruction53): + ror edi, cl +FN_PREFIX(CryptonightR_instruction54): + rol edi, cl +FN_PREFIX(CryptonightR_instruction55): + xor rdi, rsi +FN_PREFIX(CryptonightR_instruction56): + imul rbp, rsi +FN_PREFIX(CryptonightR_instruction57): + imul rbp, rsi +FN_PREFIX(CryptonightR_instruction58): + imul rbp, rsi +FN_PREFIX(CryptonightR_instruction59): + add rbp, rsi + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction60): + sub rbp, rsi +FN_PREFIX(CryptonightR_instruction61): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction62): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction63): + xor rbp, rsi +FN_PREFIX(CryptonightR_instruction64): + imul rbx, rdi +FN_PREFIX(CryptonightR_instruction65): + imul rbx, rdi +FN_PREFIX(CryptonightR_instruction66): + imul rbx, rdi +FN_PREFIX(CryptonightR_instruction67): + add rbx, rdi + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction68): + sub rbx, rdi +FN_PREFIX(CryptonightR_instruction69): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction70): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction71): + xor rbx, rdi +FN_PREFIX(CryptonightR_instruction72): + imul rsi, rdi +FN_PREFIX(CryptonightR_instruction73): + imul rsi, rdi +FN_PREFIX(CryptonightR_instruction74): + imul rsi, rdi +FN_PREFIX(CryptonightR_instruction75): + add rsi, rdi + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction76): + sub rsi, rdi +FN_PREFIX(CryptonightR_instruction77): + ror esi, cl +FN_PREFIX(CryptonightR_instruction78): + rol esi, cl +FN_PREFIX(CryptonightR_instruction79): + xor rsi, rdi +FN_PREFIX(CryptonightR_instruction80): + imul rdi, rdi +FN_PREFIX(CryptonightR_instruction81): + imul rdi, rdi +FN_PREFIX(CryptonightR_instruction82): + imul rdi, rdi +FN_PREFIX(CryptonightR_instruction83): + add rdi, r9 + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction84): + sub rdi, r9 +FN_PREFIX(CryptonightR_instruction85): + ror edi, cl +FN_PREFIX(CryptonightR_instruction86): + rol edi, cl +FN_PREFIX(CryptonightR_instruction87): + xor rdi, r9 +FN_PREFIX(CryptonightR_instruction88): + imul rbp, rdi +FN_PREFIX(CryptonightR_instruction89): + imul rbp, rdi +FN_PREFIX(CryptonightR_instruction90): + imul rbp, rdi +FN_PREFIX(CryptonightR_instruction91): + add rbp, rdi + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction92): + sub rbp, rdi +FN_PREFIX(CryptonightR_instruction93): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction94): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction95): + xor rbp, rdi +FN_PREFIX(CryptonightR_instruction96): + imul rbx, rbp +FN_PREFIX(CryptonightR_instruction97): + imul rbx, rbp +FN_PREFIX(CryptonightR_instruction98): + imul rbx, rbp +FN_PREFIX(CryptonightR_instruction99): + add rbx, rbp + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction100): + sub rbx, rbp +FN_PREFIX(CryptonightR_instruction101): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction102): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction103): + xor rbx, rbp +FN_PREFIX(CryptonightR_instruction104): + imul rsi, rbp +FN_PREFIX(CryptonightR_instruction105): + imul rsi, rbp +FN_PREFIX(CryptonightR_instruction106): + imul rsi, rbp +FN_PREFIX(CryptonightR_instruction107): + add rsi, rbp + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction108): + sub rsi, rbp +FN_PREFIX(CryptonightR_instruction109): + ror esi, cl +FN_PREFIX(CryptonightR_instruction110): + rol esi, cl +FN_PREFIX(CryptonightR_instruction111): + xor rsi, rbp +FN_PREFIX(CryptonightR_instruction112): + imul rdi, rbp +FN_PREFIX(CryptonightR_instruction113): + imul rdi, rbp +FN_PREFIX(CryptonightR_instruction114): + imul rdi, rbp +FN_PREFIX(CryptonightR_instruction115): + add rdi, rbp + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction116): + sub rdi, rbp +FN_PREFIX(CryptonightR_instruction117): + ror edi, cl +FN_PREFIX(CryptonightR_instruction118): + rol edi, cl +FN_PREFIX(CryptonightR_instruction119): + xor rdi, rbp +FN_PREFIX(CryptonightR_instruction120): + imul rbp, rbp +FN_PREFIX(CryptonightR_instruction121): + imul rbp, rbp +FN_PREFIX(CryptonightR_instruction122): + imul rbp, rbp +FN_PREFIX(CryptonightR_instruction123): + add rbp, r9 + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction124): + sub rbp, r9 +FN_PREFIX(CryptonightR_instruction125): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction126): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction127): + xor rbp, r9 +FN_PREFIX(CryptonightR_instruction128): + imul rbx, rsp +FN_PREFIX(CryptonightR_instruction129): + imul rbx, rsp +FN_PREFIX(CryptonightR_instruction130): + imul rbx, rsp +FN_PREFIX(CryptonightR_instruction131): + add rbx, rsp + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction132): + sub rbx, rsp +FN_PREFIX(CryptonightR_instruction133): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction134): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction135): + xor rbx, rsp +FN_PREFIX(CryptonightR_instruction136): + imul rsi, rsp +FN_PREFIX(CryptonightR_instruction137): + imul rsi, rsp +FN_PREFIX(CryptonightR_instruction138): + imul rsi, rsp +FN_PREFIX(CryptonightR_instruction139): + add rsi, rsp + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction140): + sub rsi, rsp +FN_PREFIX(CryptonightR_instruction141): + ror esi, cl +FN_PREFIX(CryptonightR_instruction142): + rol esi, cl +FN_PREFIX(CryptonightR_instruction143): + xor rsi, rsp +FN_PREFIX(CryptonightR_instruction144): + imul rdi, rsp +FN_PREFIX(CryptonightR_instruction145): + imul rdi, rsp +FN_PREFIX(CryptonightR_instruction146): + imul rdi, rsp +FN_PREFIX(CryptonightR_instruction147): + add rdi, rsp + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction148): + sub rdi, rsp +FN_PREFIX(CryptonightR_instruction149): + ror edi, cl +FN_PREFIX(CryptonightR_instruction150): + rol edi, cl +FN_PREFIX(CryptonightR_instruction151): + xor rdi, rsp +FN_PREFIX(CryptonightR_instruction152): + imul rbp, rsp +FN_PREFIX(CryptonightR_instruction153): + imul rbp, rsp +FN_PREFIX(CryptonightR_instruction154): + imul rbp, rsp +FN_PREFIX(CryptonightR_instruction155): + add rbp, rsp + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction156): + sub rbp, rsp +FN_PREFIX(CryptonightR_instruction157): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction158): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction159): + xor rbp, rsp +FN_PREFIX(CryptonightR_instruction160): + imul rbx, r15 +FN_PREFIX(CryptonightR_instruction161): + imul rbx, r15 +FN_PREFIX(CryptonightR_instruction162): + imul rbx, r15 +FN_PREFIX(CryptonightR_instruction163): + add rbx, r15 + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction164): + sub rbx, r15 +FN_PREFIX(CryptonightR_instruction165): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction166): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction167): + xor rbx, r15 +FN_PREFIX(CryptonightR_instruction168): + imul rsi, r15 +FN_PREFIX(CryptonightR_instruction169): + imul rsi, r15 +FN_PREFIX(CryptonightR_instruction170): + imul rsi, r15 +FN_PREFIX(CryptonightR_instruction171): + add rsi, r15 + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction172): + sub rsi, r15 +FN_PREFIX(CryptonightR_instruction173): + ror esi, cl +FN_PREFIX(CryptonightR_instruction174): + rol esi, cl +FN_PREFIX(CryptonightR_instruction175): + xor rsi, r15 +FN_PREFIX(CryptonightR_instruction176): + imul rdi, r15 +FN_PREFIX(CryptonightR_instruction177): + imul rdi, r15 +FN_PREFIX(CryptonightR_instruction178): + imul rdi, r15 +FN_PREFIX(CryptonightR_instruction179): + add rdi, r15 + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction180): + sub rdi, r15 +FN_PREFIX(CryptonightR_instruction181): + ror edi, cl +FN_PREFIX(CryptonightR_instruction182): + rol edi, cl +FN_PREFIX(CryptonightR_instruction183): + xor rdi, r15 +FN_PREFIX(CryptonightR_instruction184): + imul rbp, r15 +FN_PREFIX(CryptonightR_instruction185): + imul rbp, r15 +FN_PREFIX(CryptonightR_instruction186): + imul rbp, r15 +FN_PREFIX(CryptonightR_instruction187): + add rbp, r15 + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction188): + sub rbp, r15 +FN_PREFIX(CryptonightR_instruction189): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction190): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction191): + xor rbp, r15 +FN_PREFIX(CryptonightR_instruction192): + imul rbx, rax +FN_PREFIX(CryptonightR_instruction193): + imul rbx, rax +FN_PREFIX(CryptonightR_instruction194): + imul rbx, rax +FN_PREFIX(CryptonightR_instruction195): + add rbx, rax + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction196): + sub rbx, rax +FN_PREFIX(CryptonightR_instruction197): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction198): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction199): + xor rbx, rax +FN_PREFIX(CryptonightR_instruction200): + imul rsi, rax +FN_PREFIX(CryptonightR_instruction201): + imul rsi, rax +FN_PREFIX(CryptonightR_instruction202): + imul rsi, rax +FN_PREFIX(CryptonightR_instruction203): + add rsi, rax + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction204): + sub rsi, rax +FN_PREFIX(CryptonightR_instruction205): + ror esi, cl +FN_PREFIX(CryptonightR_instruction206): + rol esi, cl +FN_PREFIX(CryptonightR_instruction207): + xor rsi, rax +FN_PREFIX(CryptonightR_instruction208): + imul rdi, rax +FN_PREFIX(CryptonightR_instruction209): + imul rdi, rax +FN_PREFIX(CryptonightR_instruction210): + imul rdi, rax +FN_PREFIX(CryptonightR_instruction211): + add rdi, rax + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction212): + sub rdi, rax +FN_PREFIX(CryptonightR_instruction213): + ror edi, cl +FN_PREFIX(CryptonightR_instruction214): + rol edi, cl +FN_PREFIX(CryptonightR_instruction215): + xor rdi, rax +FN_PREFIX(CryptonightR_instruction216): + imul rbp, rax +FN_PREFIX(CryptonightR_instruction217): + imul rbp, rax +FN_PREFIX(CryptonightR_instruction218): + imul rbp, rax +FN_PREFIX(CryptonightR_instruction219): + add rbp, rax + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction220): + sub rbp, rax +FN_PREFIX(CryptonightR_instruction221): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction222): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction223): + xor rbp, rax +FN_PREFIX(CryptonightR_instruction224): + imul rbx, rdx +FN_PREFIX(CryptonightR_instruction225): + imul rbx, rdx +FN_PREFIX(CryptonightR_instruction226): + imul rbx, rdx +FN_PREFIX(CryptonightR_instruction227): + add rbx, rdx + add rbx, 2147483647 +FN_PREFIX(CryptonightR_instruction228): + sub rbx, rdx +FN_PREFIX(CryptonightR_instruction229): + ror ebx, cl +FN_PREFIX(CryptonightR_instruction230): + rol ebx, cl +FN_PREFIX(CryptonightR_instruction231): + xor rbx, rdx +FN_PREFIX(CryptonightR_instruction232): + imul rsi, rdx +FN_PREFIX(CryptonightR_instruction233): + imul rsi, rdx +FN_PREFIX(CryptonightR_instruction234): + imul rsi, rdx +FN_PREFIX(CryptonightR_instruction235): + add rsi, rdx + add rsi, 2147483647 +FN_PREFIX(CryptonightR_instruction236): + sub rsi, rdx +FN_PREFIX(CryptonightR_instruction237): + ror esi, cl +FN_PREFIX(CryptonightR_instruction238): + rol esi, cl +FN_PREFIX(CryptonightR_instruction239): + xor rsi, rdx +FN_PREFIX(CryptonightR_instruction240): + imul rdi, rdx +FN_PREFIX(CryptonightR_instruction241): + imul rdi, rdx +FN_PREFIX(CryptonightR_instruction242): + imul rdi, rdx +FN_PREFIX(CryptonightR_instruction243): + add rdi, rdx + add rdi, 2147483647 +FN_PREFIX(CryptonightR_instruction244): + sub rdi, rdx +FN_PREFIX(CryptonightR_instruction245): + ror edi, cl +FN_PREFIX(CryptonightR_instruction246): + rol edi, cl +FN_PREFIX(CryptonightR_instruction247): + xor rdi, rdx +FN_PREFIX(CryptonightR_instruction248): + imul rbp, rdx +FN_PREFIX(CryptonightR_instruction249): + imul rbp, rdx +FN_PREFIX(CryptonightR_instruction250): + imul rbp, rdx +FN_PREFIX(CryptonightR_instruction251): + add rbp, rdx + add rbp, 2147483647 +FN_PREFIX(CryptonightR_instruction252): + sub rbp, rdx +FN_PREFIX(CryptonightR_instruction253): + ror ebp, cl +FN_PREFIX(CryptonightR_instruction254): + rol ebp, cl +FN_PREFIX(CryptonightR_instruction255): + xor rbp, rdx +FN_PREFIX(CryptonightR_instruction256): + imul rbx, rbx +FN_PREFIX(CryptonightR_instruction_mov0): + +FN_PREFIX(CryptonightR_instruction_mov1): + +FN_PREFIX(CryptonightR_instruction_mov2): + +FN_PREFIX(CryptonightR_instruction_mov3): + +FN_PREFIX(CryptonightR_instruction_mov4): + +FN_PREFIX(CryptonightR_instruction_mov5): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov6): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov7): + +FN_PREFIX(CryptonightR_instruction_mov8): + +FN_PREFIX(CryptonightR_instruction_mov9): + +FN_PREFIX(CryptonightR_instruction_mov10): + +FN_PREFIX(CryptonightR_instruction_mov11): + +FN_PREFIX(CryptonightR_instruction_mov12): + +FN_PREFIX(CryptonightR_instruction_mov13): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov14): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov15): + +FN_PREFIX(CryptonightR_instruction_mov16): + +FN_PREFIX(CryptonightR_instruction_mov17): + +FN_PREFIX(CryptonightR_instruction_mov18): + +FN_PREFIX(CryptonightR_instruction_mov19): + +FN_PREFIX(CryptonightR_instruction_mov20): + +FN_PREFIX(CryptonightR_instruction_mov21): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov22): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov23): + +FN_PREFIX(CryptonightR_instruction_mov24): + +FN_PREFIX(CryptonightR_instruction_mov25): + +FN_PREFIX(CryptonightR_instruction_mov26): + +FN_PREFIX(CryptonightR_instruction_mov27): + +FN_PREFIX(CryptonightR_instruction_mov28): + +FN_PREFIX(CryptonightR_instruction_mov29): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov30): + mov rcx, rbx +FN_PREFIX(CryptonightR_instruction_mov31): + +FN_PREFIX(CryptonightR_instruction_mov32): + +FN_PREFIX(CryptonightR_instruction_mov33): + +FN_PREFIX(CryptonightR_instruction_mov34): + +FN_PREFIX(CryptonightR_instruction_mov35): + +FN_PREFIX(CryptonightR_instruction_mov36): + +FN_PREFIX(CryptonightR_instruction_mov37): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov38): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov39): + +FN_PREFIX(CryptonightR_instruction_mov40): + +FN_PREFIX(CryptonightR_instruction_mov41): + +FN_PREFIX(CryptonightR_instruction_mov42): + +FN_PREFIX(CryptonightR_instruction_mov43): + +FN_PREFIX(CryptonightR_instruction_mov44): + +FN_PREFIX(CryptonightR_instruction_mov45): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov46): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov47): + +FN_PREFIX(CryptonightR_instruction_mov48): + +FN_PREFIX(CryptonightR_instruction_mov49): + +FN_PREFIX(CryptonightR_instruction_mov50): + +FN_PREFIX(CryptonightR_instruction_mov51): + +FN_PREFIX(CryptonightR_instruction_mov52): + +FN_PREFIX(CryptonightR_instruction_mov53): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov54): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov55): + +FN_PREFIX(CryptonightR_instruction_mov56): + +FN_PREFIX(CryptonightR_instruction_mov57): + +FN_PREFIX(CryptonightR_instruction_mov58): + +FN_PREFIX(CryptonightR_instruction_mov59): + +FN_PREFIX(CryptonightR_instruction_mov60): + +FN_PREFIX(CryptonightR_instruction_mov61): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov62): + mov rcx, rsi +FN_PREFIX(CryptonightR_instruction_mov63): + +FN_PREFIX(CryptonightR_instruction_mov64): + +FN_PREFIX(CryptonightR_instruction_mov65): + +FN_PREFIX(CryptonightR_instruction_mov66): + +FN_PREFIX(CryptonightR_instruction_mov67): + +FN_PREFIX(CryptonightR_instruction_mov68): + +FN_PREFIX(CryptonightR_instruction_mov69): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov70): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov71): + +FN_PREFIX(CryptonightR_instruction_mov72): + +FN_PREFIX(CryptonightR_instruction_mov73): + +FN_PREFIX(CryptonightR_instruction_mov74): + +FN_PREFIX(CryptonightR_instruction_mov75): + +FN_PREFIX(CryptonightR_instruction_mov76): + +FN_PREFIX(CryptonightR_instruction_mov77): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov78): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov79): + +FN_PREFIX(CryptonightR_instruction_mov80): + +FN_PREFIX(CryptonightR_instruction_mov81): + +FN_PREFIX(CryptonightR_instruction_mov82): + +FN_PREFIX(CryptonightR_instruction_mov83): + +FN_PREFIX(CryptonightR_instruction_mov84): + +FN_PREFIX(CryptonightR_instruction_mov85): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov86): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov87): + +FN_PREFIX(CryptonightR_instruction_mov88): + +FN_PREFIX(CryptonightR_instruction_mov89): + +FN_PREFIX(CryptonightR_instruction_mov90): + +FN_PREFIX(CryptonightR_instruction_mov91): + +FN_PREFIX(CryptonightR_instruction_mov92): + +FN_PREFIX(CryptonightR_instruction_mov93): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov94): + mov rcx, rdi +FN_PREFIX(CryptonightR_instruction_mov95): + +FN_PREFIX(CryptonightR_instruction_mov96): + +FN_PREFIX(CryptonightR_instruction_mov97): + +FN_PREFIX(CryptonightR_instruction_mov98): + +FN_PREFIX(CryptonightR_instruction_mov99): + +FN_PREFIX(CryptonightR_instruction_mov100): + +FN_PREFIX(CryptonightR_instruction_mov101): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov102): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov103): + +FN_PREFIX(CryptonightR_instruction_mov104): + +FN_PREFIX(CryptonightR_instruction_mov105): + +FN_PREFIX(CryptonightR_instruction_mov106): + +FN_PREFIX(CryptonightR_instruction_mov107): + +FN_PREFIX(CryptonightR_instruction_mov108): + +FN_PREFIX(CryptonightR_instruction_mov109): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov110): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov111): + +FN_PREFIX(CryptonightR_instruction_mov112): + +FN_PREFIX(CryptonightR_instruction_mov113): + +FN_PREFIX(CryptonightR_instruction_mov114): + +FN_PREFIX(CryptonightR_instruction_mov115): + +FN_PREFIX(CryptonightR_instruction_mov116): + +FN_PREFIX(CryptonightR_instruction_mov117): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov118): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov119): + +FN_PREFIX(CryptonightR_instruction_mov120): + +FN_PREFIX(CryptonightR_instruction_mov121): + +FN_PREFIX(CryptonightR_instruction_mov122): + +FN_PREFIX(CryptonightR_instruction_mov123): + +FN_PREFIX(CryptonightR_instruction_mov124): + +FN_PREFIX(CryptonightR_instruction_mov125): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov126): + mov rcx, rbp +FN_PREFIX(CryptonightR_instruction_mov127): + +FN_PREFIX(CryptonightR_instruction_mov128): + +FN_PREFIX(CryptonightR_instruction_mov129): + +FN_PREFIX(CryptonightR_instruction_mov130): + +FN_PREFIX(CryptonightR_instruction_mov131): + +FN_PREFIX(CryptonightR_instruction_mov132): + +FN_PREFIX(CryptonightR_instruction_mov133): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov134): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov135): + +FN_PREFIX(CryptonightR_instruction_mov136): + +FN_PREFIX(CryptonightR_instruction_mov137): + +FN_PREFIX(CryptonightR_instruction_mov138): + +FN_PREFIX(CryptonightR_instruction_mov139): + +FN_PREFIX(CryptonightR_instruction_mov140): + +FN_PREFIX(CryptonightR_instruction_mov141): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov142): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov143): + +FN_PREFIX(CryptonightR_instruction_mov144): + +FN_PREFIX(CryptonightR_instruction_mov145): + +FN_PREFIX(CryptonightR_instruction_mov146): + +FN_PREFIX(CryptonightR_instruction_mov147): + +FN_PREFIX(CryptonightR_instruction_mov148): + +FN_PREFIX(CryptonightR_instruction_mov149): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov150): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov151): + +FN_PREFIX(CryptonightR_instruction_mov152): + +FN_PREFIX(CryptonightR_instruction_mov153): + +FN_PREFIX(CryptonightR_instruction_mov154): + +FN_PREFIX(CryptonightR_instruction_mov155): + +FN_PREFIX(CryptonightR_instruction_mov156): + +FN_PREFIX(CryptonightR_instruction_mov157): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov158): + mov rcx, rsp +FN_PREFIX(CryptonightR_instruction_mov159): + +FN_PREFIX(CryptonightR_instruction_mov160): + +FN_PREFIX(CryptonightR_instruction_mov161): + +FN_PREFIX(CryptonightR_instruction_mov162): + +FN_PREFIX(CryptonightR_instruction_mov163): + +FN_PREFIX(CryptonightR_instruction_mov164): + +FN_PREFIX(CryptonightR_instruction_mov165): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov166): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov167): + +FN_PREFIX(CryptonightR_instruction_mov168): + +FN_PREFIX(CryptonightR_instruction_mov169): + +FN_PREFIX(CryptonightR_instruction_mov170): + +FN_PREFIX(CryptonightR_instruction_mov171): + +FN_PREFIX(CryptonightR_instruction_mov172): + +FN_PREFIX(CryptonightR_instruction_mov173): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov174): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov175): + +FN_PREFIX(CryptonightR_instruction_mov176): + +FN_PREFIX(CryptonightR_instruction_mov177): + +FN_PREFIX(CryptonightR_instruction_mov178): + +FN_PREFIX(CryptonightR_instruction_mov179): + +FN_PREFIX(CryptonightR_instruction_mov180): + +FN_PREFIX(CryptonightR_instruction_mov181): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov182): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov183): + +FN_PREFIX(CryptonightR_instruction_mov184): + +FN_PREFIX(CryptonightR_instruction_mov185): + +FN_PREFIX(CryptonightR_instruction_mov186): + +FN_PREFIX(CryptonightR_instruction_mov187): + +FN_PREFIX(CryptonightR_instruction_mov188): + +FN_PREFIX(CryptonightR_instruction_mov189): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov190): + mov rcx, r15 +FN_PREFIX(CryptonightR_instruction_mov191): + +FN_PREFIX(CryptonightR_instruction_mov192): + +FN_PREFIX(CryptonightR_instruction_mov193): + +FN_PREFIX(CryptonightR_instruction_mov194): + +FN_PREFIX(CryptonightR_instruction_mov195): + +FN_PREFIX(CryptonightR_instruction_mov196): + +FN_PREFIX(CryptonightR_instruction_mov197): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov198): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov199): + +FN_PREFIX(CryptonightR_instruction_mov200): + +FN_PREFIX(CryptonightR_instruction_mov201): + +FN_PREFIX(CryptonightR_instruction_mov202): + +FN_PREFIX(CryptonightR_instruction_mov203): + +FN_PREFIX(CryptonightR_instruction_mov204): + +FN_PREFIX(CryptonightR_instruction_mov205): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov206): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov207): + +FN_PREFIX(CryptonightR_instruction_mov208): + +FN_PREFIX(CryptonightR_instruction_mov209): + +FN_PREFIX(CryptonightR_instruction_mov210): + +FN_PREFIX(CryptonightR_instruction_mov211): + +FN_PREFIX(CryptonightR_instruction_mov212): + +FN_PREFIX(CryptonightR_instruction_mov213): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov214): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov215): + +FN_PREFIX(CryptonightR_instruction_mov216): + +FN_PREFIX(CryptonightR_instruction_mov217): + +FN_PREFIX(CryptonightR_instruction_mov218): + +FN_PREFIX(CryptonightR_instruction_mov219): + +FN_PREFIX(CryptonightR_instruction_mov220): + +FN_PREFIX(CryptonightR_instruction_mov221): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov222): + mov rcx, rax +FN_PREFIX(CryptonightR_instruction_mov223): + +FN_PREFIX(CryptonightR_instruction_mov224): + +FN_PREFIX(CryptonightR_instruction_mov225): + +FN_PREFIX(CryptonightR_instruction_mov226): + +FN_PREFIX(CryptonightR_instruction_mov227): + +FN_PREFIX(CryptonightR_instruction_mov228): + +FN_PREFIX(CryptonightR_instruction_mov229): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov230): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov231): + +FN_PREFIX(CryptonightR_instruction_mov232): + +FN_PREFIX(CryptonightR_instruction_mov233): + +FN_PREFIX(CryptonightR_instruction_mov234): + +FN_PREFIX(CryptonightR_instruction_mov235): + +FN_PREFIX(CryptonightR_instruction_mov236): + +FN_PREFIX(CryptonightR_instruction_mov237): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov238): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov239): + +FN_PREFIX(CryptonightR_instruction_mov240): + +FN_PREFIX(CryptonightR_instruction_mov241): + +FN_PREFIX(CryptonightR_instruction_mov242): + +FN_PREFIX(CryptonightR_instruction_mov243): + +FN_PREFIX(CryptonightR_instruction_mov244): + +FN_PREFIX(CryptonightR_instruction_mov245): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov246): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov247): + +FN_PREFIX(CryptonightR_instruction_mov248): + +FN_PREFIX(CryptonightR_instruction_mov249): + +FN_PREFIX(CryptonightR_instruction_mov250): + +FN_PREFIX(CryptonightR_instruction_mov251): + +FN_PREFIX(CryptonightR_instruction_mov252): + +FN_PREFIX(CryptonightR_instruction_mov253): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov254): + mov rcx, rdx +FN_PREFIX(CryptonightR_instruction_mov255): + +FN_PREFIX(CryptonightR_instruction_mov256): diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.asm b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.asm new file mode 100644 index 000000000..25b72c3c0 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.asm @@ -0,0 +1,1583 @@ +; Auto-generated file, do not edit + +_TEXT_CN_TEMPLATE SEGMENT PAGE READ EXECUTE +PUBLIC CryptonightR_instruction0 +PUBLIC CryptonightR_instruction1 +PUBLIC CryptonightR_instruction2 +PUBLIC CryptonightR_instruction3 +PUBLIC CryptonightR_instruction4 +PUBLIC CryptonightR_instruction5 +PUBLIC CryptonightR_instruction6 +PUBLIC CryptonightR_instruction7 +PUBLIC CryptonightR_instruction8 +PUBLIC CryptonightR_instruction9 +PUBLIC CryptonightR_instruction10 +PUBLIC CryptonightR_instruction11 +PUBLIC CryptonightR_instruction12 +PUBLIC CryptonightR_instruction13 +PUBLIC CryptonightR_instruction14 +PUBLIC CryptonightR_instruction15 +PUBLIC CryptonightR_instruction16 +PUBLIC CryptonightR_instruction17 +PUBLIC CryptonightR_instruction18 +PUBLIC CryptonightR_instruction19 +PUBLIC CryptonightR_instruction20 +PUBLIC CryptonightR_instruction21 +PUBLIC CryptonightR_instruction22 +PUBLIC CryptonightR_instruction23 +PUBLIC CryptonightR_instruction24 +PUBLIC CryptonightR_instruction25 +PUBLIC CryptonightR_instruction26 +PUBLIC CryptonightR_instruction27 +PUBLIC CryptonightR_instruction28 +PUBLIC CryptonightR_instruction29 +PUBLIC CryptonightR_instruction30 +PUBLIC CryptonightR_instruction31 +PUBLIC CryptonightR_instruction32 +PUBLIC CryptonightR_instruction33 +PUBLIC CryptonightR_instruction34 +PUBLIC CryptonightR_instruction35 +PUBLIC CryptonightR_instruction36 +PUBLIC CryptonightR_instruction37 +PUBLIC CryptonightR_instruction38 +PUBLIC CryptonightR_instruction39 +PUBLIC CryptonightR_instruction40 +PUBLIC CryptonightR_instruction41 +PUBLIC CryptonightR_instruction42 +PUBLIC CryptonightR_instruction43 +PUBLIC CryptonightR_instruction44 +PUBLIC CryptonightR_instruction45 +PUBLIC CryptonightR_instruction46 +PUBLIC CryptonightR_instruction47 +PUBLIC CryptonightR_instruction48 +PUBLIC CryptonightR_instruction49 +PUBLIC CryptonightR_instruction50 +PUBLIC CryptonightR_instruction51 +PUBLIC CryptonightR_instruction52 +PUBLIC CryptonightR_instruction53 +PUBLIC CryptonightR_instruction54 +PUBLIC CryptonightR_instruction55 +PUBLIC CryptonightR_instruction56 +PUBLIC CryptonightR_instruction57 +PUBLIC CryptonightR_instruction58 +PUBLIC CryptonightR_instruction59 +PUBLIC CryptonightR_instruction60 +PUBLIC CryptonightR_instruction61 +PUBLIC CryptonightR_instruction62 +PUBLIC CryptonightR_instruction63 +PUBLIC CryptonightR_instruction64 +PUBLIC CryptonightR_instruction65 +PUBLIC CryptonightR_instruction66 +PUBLIC CryptonightR_instruction67 +PUBLIC CryptonightR_instruction68 +PUBLIC CryptonightR_instruction69 +PUBLIC CryptonightR_instruction70 +PUBLIC CryptonightR_instruction71 +PUBLIC CryptonightR_instruction72 +PUBLIC CryptonightR_instruction73 +PUBLIC CryptonightR_instruction74 +PUBLIC CryptonightR_instruction75 +PUBLIC CryptonightR_instruction76 +PUBLIC CryptonightR_instruction77 +PUBLIC CryptonightR_instruction78 +PUBLIC CryptonightR_instruction79 +PUBLIC CryptonightR_instruction80 +PUBLIC CryptonightR_instruction81 +PUBLIC CryptonightR_instruction82 +PUBLIC CryptonightR_instruction83 +PUBLIC CryptonightR_instruction84 +PUBLIC CryptonightR_instruction85 +PUBLIC CryptonightR_instruction86 +PUBLIC CryptonightR_instruction87 +PUBLIC CryptonightR_instruction88 +PUBLIC CryptonightR_instruction89 +PUBLIC CryptonightR_instruction90 +PUBLIC CryptonightR_instruction91 +PUBLIC CryptonightR_instruction92 +PUBLIC CryptonightR_instruction93 +PUBLIC CryptonightR_instruction94 +PUBLIC CryptonightR_instruction95 +PUBLIC CryptonightR_instruction96 +PUBLIC CryptonightR_instruction97 +PUBLIC CryptonightR_instruction98 +PUBLIC CryptonightR_instruction99 +PUBLIC CryptonightR_instruction100 +PUBLIC CryptonightR_instruction101 +PUBLIC CryptonightR_instruction102 +PUBLIC CryptonightR_instruction103 +PUBLIC CryptonightR_instruction104 +PUBLIC CryptonightR_instruction105 +PUBLIC CryptonightR_instruction106 +PUBLIC CryptonightR_instruction107 +PUBLIC CryptonightR_instruction108 +PUBLIC CryptonightR_instruction109 +PUBLIC CryptonightR_instruction110 +PUBLIC CryptonightR_instruction111 +PUBLIC CryptonightR_instruction112 +PUBLIC CryptonightR_instruction113 +PUBLIC CryptonightR_instruction114 +PUBLIC CryptonightR_instruction115 +PUBLIC CryptonightR_instruction116 +PUBLIC CryptonightR_instruction117 +PUBLIC CryptonightR_instruction118 +PUBLIC CryptonightR_instruction119 +PUBLIC CryptonightR_instruction120 +PUBLIC CryptonightR_instruction121 +PUBLIC CryptonightR_instruction122 +PUBLIC CryptonightR_instruction123 +PUBLIC CryptonightR_instruction124 +PUBLIC CryptonightR_instruction125 +PUBLIC CryptonightR_instruction126 +PUBLIC CryptonightR_instruction127 +PUBLIC CryptonightR_instruction128 +PUBLIC CryptonightR_instruction129 +PUBLIC CryptonightR_instruction130 +PUBLIC CryptonightR_instruction131 +PUBLIC CryptonightR_instruction132 +PUBLIC CryptonightR_instruction133 +PUBLIC CryptonightR_instruction134 +PUBLIC CryptonightR_instruction135 +PUBLIC CryptonightR_instruction136 +PUBLIC CryptonightR_instruction137 +PUBLIC CryptonightR_instruction138 +PUBLIC CryptonightR_instruction139 +PUBLIC CryptonightR_instruction140 +PUBLIC CryptonightR_instruction141 +PUBLIC CryptonightR_instruction142 +PUBLIC CryptonightR_instruction143 +PUBLIC CryptonightR_instruction144 +PUBLIC CryptonightR_instruction145 +PUBLIC CryptonightR_instruction146 +PUBLIC CryptonightR_instruction147 +PUBLIC CryptonightR_instruction148 +PUBLIC CryptonightR_instruction149 +PUBLIC CryptonightR_instruction150 +PUBLIC CryptonightR_instruction151 +PUBLIC CryptonightR_instruction152 +PUBLIC CryptonightR_instruction153 +PUBLIC CryptonightR_instruction154 +PUBLIC CryptonightR_instruction155 +PUBLIC CryptonightR_instruction156 +PUBLIC CryptonightR_instruction157 +PUBLIC CryptonightR_instruction158 +PUBLIC CryptonightR_instruction159 +PUBLIC CryptonightR_instruction160 +PUBLIC CryptonightR_instruction161 +PUBLIC CryptonightR_instruction162 +PUBLIC CryptonightR_instruction163 +PUBLIC CryptonightR_instruction164 +PUBLIC CryptonightR_instruction165 +PUBLIC CryptonightR_instruction166 +PUBLIC CryptonightR_instruction167 +PUBLIC CryptonightR_instruction168 +PUBLIC CryptonightR_instruction169 +PUBLIC CryptonightR_instruction170 +PUBLIC CryptonightR_instruction171 +PUBLIC CryptonightR_instruction172 +PUBLIC CryptonightR_instruction173 +PUBLIC CryptonightR_instruction174 +PUBLIC CryptonightR_instruction175 +PUBLIC CryptonightR_instruction176 +PUBLIC CryptonightR_instruction177 +PUBLIC CryptonightR_instruction178 +PUBLIC CryptonightR_instruction179 +PUBLIC CryptonightR_instruction180 +PUBLIC CryptonightR_instruction181 +PUBLIC CryptonightR_instruction182 +PUBLIC CryptonightR_instruction183 +PUBLIC CryptonightR_instruction184 +PUBLIC CryptonightR_instruction185 +PUBLIC CryptonightR_instruction186 +PUBLIC CryptonightR_instruction187 +PUBLIC CryptonightR_instruction188 +PUBLIC CryptonightR_instruction189 +PUBLIC CryptonightR_instruction190 +PUBLIC CryptonightR_instruction191 +PUBLIC CryptonightR_instruction192 +PUBLIC CryptonightR_instruction193 +PUBLIC CryptonightR_instruction194 +PUBLIC CryptonightR_instruction195 +PUBLIC CryptonightR_instruction196 +PUBLIC CryptonightR_instruction197 +PUBLIC CryptonightR_instruction198 +PUBLIC CryptonightR_instruction199 +PUBLIC CryptonightR_instruction200 +PUBLIC CryptonightR_instruction201 +PUBLIC CryptonightR_instruction202 +PUBLIC CryptonightR_instruction203 +PUBLIC CryptonightR_instruction204 +PUBLIC CryptonightR_instruction205 +PUBLIC CryptonightR_instruction206 +PUBLIC CryptonightR_instruction207 +PUBLIC CryptonightR_instruction208 +PUBLIC CryptonightR_instruction209 +PUBLIC CryptonightR_instruction210 +PUBLIC CryptonightR_instruction211 +PUBLIC CryptonightR_instruction212 +PUBLIC CryptonightR_instruction213 +PUBLIC CryptonightR_instruction214 +PUBLIC CryptonightR_instruction215 +PUBLIC CryptonightR_instruction216 +PUBLIC CryptonightR_instruction217 +PUBLIC CryptonightR_instruction218 +PUBLIC CryptonightR_instruction219 +PUBLIC CryptonightR_instruction220 +PUBLIC CryptonightR_instruction221 +PUBLIC CryptonightR_instruction222 +PUBLIC CryptonightR_instruction223 +PUBLIC CryptonightR_instruction224 +PUBLIC CryptonightR_instruction225 +PUBLIC CryptonightR_instruction226 +PUBLIC CryptonightR_instruction227 +PUBLIC CryptonightR_instruction228 +PUBLIC CryptonightR_instruction229 +PUBLIC CryptonightR_instruction230 +PUBLIC CryptonightR_instruction231 +PUBLIC CryptonightR_instruction232 +PUBLIC CryptonightR_instruction233 +PUBLIC CryptonightR_instruction234 +PUBLIC CryptonightR_instruction235 +PUBLIC CryptonightR_instruction236 +PUBLIC CryptonightR_instruction237 +PUBLIC CryptonightR_instruction238 +PUBLIC CryptonightR_instruction239 +PUBLIC CryptonightR_instruction240 +PUBLIC CryptonightR_instruction241 +PUBLIC CryptonightR_instruction242 +PUBLIC CryptonightR_instruction243 +PUBLIC CryptonightR_instruction244 +PUBLIC CryptonightR_instruction245 +PUBLIC CryptonightR_instruction246 +PUBLIC CryptonightR_instruction247 +PUBLIC CryptonightR_instruction248 +PUBLIC CryptonightR_instruction249 +PUBLIC CryptonightR_instruction250 +PUBLIC CryptonightR_instruction251 +PUBLIC CryptonightR_instruction252 +PUBLIC CryptonightR_instruction253 +PUBLIC CryptonightR_instruction254 +PUBLIC CryptonightR_instruction255 +PUBLIC CryptonightR_instruction256 +PUBLIC CryptonightR_instruction_mov0 +PUBLIC CryptonightR_instruction_mov1 +PUBLIC CryptonightR_instruction_mov2 +PUBLIC CryptonightR_instruction_mov3 +PUBLIC CryptonightR_instruction_mov4 +PUBLIC CryptonightR_instruction_mov5 +PUBLIC CryptonightR_instruction_mov6 +PUBLIC CryptonightR_instruction_mov7 +PUBLIC CryptonightR_instruction_mov8 +PUBLIC CryptonightR_instruction_mov9 +PUBLIC CryptonightR_instruction_mov10 +PUBLIC CryptonightR_instruction_mov11 +PUBLIC CryptonightR_instruction_mov12 +PUBLIC CryptonightR_instruction_mov13 +PUBLIC CryptonightR_instruction_mov14 +PUBLIC CryptonightR_instruction_mov15 +PUBLIC CryptonightR_instruction_mov16 +PUBLIC CryptonightR_instruction_mov17 +PUBLIC CryptonightR_instruction_mov18 +PUBLIC CryptonightR_instruction_mov19 +PUBLIC CryptonightR_instruction_mov20 +PUBLIC CryptonightR_instruction_mov21 +PUBLIC CryptonightR_instruction_mov22 +PUBLIC CryptonightR_instruction_mov23 +PUBLIC CryptonightR_instruction_mov24 +PUBLIC CryptonightR_instruction_mov25 +PUBLIC CryptonightR_instruction_mov26 +PUBLIC CryptonightR_instruction_mov27 +PUBLIC CryptonightR_instruction_mov28 +PUBLIC CryptonightR_instruction_mov29 +PUBLIC CryptonightR_instruction_mov30 +PUBLIC CryptonightR_instruction_mov31 +PUBLIC CryptonightR_instruction_mov32 +PUBLIC CryptonightR_instruction_mov33 +PUBLIC CryptonightR_instruction_mov34 +PUBLIC CryptonightR_instruction_mov35 +PUBLIC CryptonightR_instruction_mov36 +PUBLIC CryptonightR_instruction_mov37 +PUBLIC CryptonightR_instruction_mov38 +PUBLIC CryptonightR_instruction_mov39 +PUBLIC CryptonightR_instruction_mov40 +PUBLIC CryptonightR_instruction_mov41 +PUBLIC CryptonightR_instruction_mov42 +PUBLIC CryptonightR_instruction_mov43 +PUBLIC CryptonightR_instruction_mov44 +PUBLIC CryptonightR_instruction_mov45 +PUBLIC CryptonightR_instruction_mov46 +PUBLIC CryptonightR_instruction_mov47 +PUBLIC CryptonightR_instruction_mov48 +PUBLIC CryptonightR_instruction_mov49 +PUBLIC CryptonightR_instruction_mov50 +PUBLIC CryptonightR_instruction_mov51 +PUBLIC CryptonightR_instruction_mov52 +PUBLIC CryptonightR_instruction_mov53 +PUBLIC CryptonightR_instruction_mov54 +PUBLIC CryptonightR_instruction_mov55 +PUBLIC CryptonightR_instruction_mov56 +PUBLIC CryptonightR_instruction_mov57 +PUBLIC CryptonightR_instruction_mov58 +PUBLIC CryptonightR_instruction_mov59 +PUBLIC CryptonightR_instruction_mov60 +PUBLIC CryptonightR_instruction_mov61 +PUBLIC CryptonightR_instruction_mov62 +PUBLIC CryptonightR_instruction_mov63 +PUBLIC CryptonightR_instruction_mov64 +PUBLIC CryptonightR_instruction_mov65 +PUBLIC CryptonightR_instruction_mov66 +PUBLIC CryptonightR_instruction_mov67 +PUBLIC CryptonightR_instruction_mov68 +PUBLIC CryptonightR_instruction_mov69 +PUBLIC CryptonightR_instruction_mov70 +PUBLIC CryptonightR_instruction_mov71 +PUBLIC CryptonightR_instruction_mov72 +PUBLIC CryptonightR_instruction_mov73 +PUBLIC CryptonightR_instruction_mov74 +PUBLIC CryptonightR_instruction_mov75 +PUBLIC CryptonightR_instruction_mov76 +PUBLIC CryptonightR_instruction_mov77 +PUBLIC CryptonightR_instruction_mov78 +PUBLIC CryptonightR_instruction_mov79 +PUBLIC CryptonightR_instruction_mov80 +PUBLIC CryptonightR_instruction_mov81 +PUBLIC CryptonightR_instruction_mov82 +PUBLIC CryptonightR_instruction_mov83 +PUBLIC CryptonightR_instruction_mov84 +PUBLIC CryptonightR_instruction_mov85 +PUBLIC CryptonightR_instruction_mov86 +PUBLIC CryptonightR_instruction_mov87 +PUBLIC CryptonightR_instruction_mov88 +PUBLIC CryptonightR_instruction_mov89 +PUBLIC CryptonightR_instruction_mov90 +PUBLIC CryptonightR_instruction_mov91 +PUBLIC CryptonightR_instruction_mov92 +PUBLIC CryptonightR_instruction_mov93 +PUBLIC CryptonightR_instruction_mov94 +PUBLIC CryptonightR_instruction_mov95 +PUBLIC CryptonightR_instruction_mov96 +PUBLIC CryptonightR_instruction_mov97 +PUBLIC CryptonightR_instruction_mov98 +PUBLIC CryptonightR_instruction_mov99 +PUBLIC CryptonightR_instruction_mov100 +PUBLIC CryptonightR_instruction_mov101 +PUBLIC CryptonightR_instruction_mov102 +PUBLIC CryptonightR_instruction_mov103 +PUBLIC CryptonightR_instruction_mov104 +PUBLIC CryptonightR_instruction_mov105 +PUBLIC CryptonightR_instruction_mov106 +PUBLIC CryptonightR_instruction_mov107 +PUBLIC CryptonightR_instruction_mov108 +PUBLIC CryptonightR_instruction_mov109 +PUBLIC CryptonightR_instruction_mov110 +PUBLIC CryptonightR_instruction_mov111 +PUBLIC CryptonightR_instruction_mov112 +PUBLIC CryptonightR_instruction_mov113 +PUBLIC CryptonightR_instruction_mov114 +PUBLIC CryptonightR_instruction_mov115 +PUBLIC CryptonightR_instruction_mov116 +PUBLIC CryptonightR_instruction_mov117 +PUBLIC CryptonightR_instruction_mov118 +PUBLIC CryptonightR_instruction_mov119 +PUBLIC CryptonightR_instruction_mov120 +PUBLIC CryptonightR_instruction_mov121 +PUBLIC CryptonightR_instruction_mov122 +PUBLIC CryptonightR_instruction_mov123 +PUBLIC CryptonightR_instruction_mov124 +PUBLIC CryptonightR_instruction_mov125 +PUBLIC CryptonightR_instruction_mov126 +PUBLIC CryptonightR_instruction_mov127 +PUBLIC CryptonightR_instruction_mov128 +PUBLIC CryptonightR_instruction_mov129 +PUBLIC CryptonightR_instruction_mov130 +PUBLIC CryptonightR_instruction_mov131 +PUBLIC CryptonightR_instruction_mov132 +PUBLIC CryptonightR_instruction_mov133 +PUBLIC CryptonightR_instruction_mov134 +PUBLIC CryptonightR_instruction_mov135 +PUBLIC CryptonightR_instruction_mov136 +PUBLIC CryptonightR_instruction_mov137 +PUBLIC CryptonightR_instruction_mov138 +PUBLIC CryptonightR_instruction_mov139 +PUBLIC CryptonightR_instruction_mov140 +PUBLIC CryptonightR_instruction_mov141 +PUBLIC CryptonightR_instruction_mov142 +PUBLIC CryptonightR_instruction_mov143 +PUBLIC CryptonightR_instruction_mov144 +PUBLIC CryptonightR_instruction_mov145 +PUBLIC CryptonightR_instruction_mov146 +PUBLIC CryptonightR_instruction_mov147 +PUBLIC CryptonightR_instruction_mov148 +PUBLIC CryptonightR_instruction_mov149 +PUBLIC CryptonightR_instruction_mov150 +PUBLIC CryptonightR_instruction_mov151 +PUBLIC CryptonightR_instruction_mov152 +PUBLIC CryptonightR_instruction_mov153 +PUBLIC CryptonightR_instruction_mov154 +PUBLIC CryptonightR_instruction_mov155 +PUBLIC CryptonightR_instruction_mov156 +PUBLIC CryptonightR_instruction_mov157 +PUBLIC CryptonightR_instruction_mov158 +PUBLIC CryptonightR_instruction_mov159 +PUBLIC CryptonightR_instruction_mov160 +PUBLIC CryptonightR_instruction_mov161 +PUBLIC CryptonightR_instruction_mov162 +PUBLIC CryptonightR_instruction_mov163 +PUBLIC CryptonightR_instruction_mov164 +PUBLIC CryptonightR_instruction_mov165 +PUBLIC CryptonightR_instruction_mov166 +PUBLIC CryptonightR_instruction_mov167 +PUBLIC CryptonightR_instruction_mov168 +PUBLIC CryptonightR_instruction_mov169 +PUBLIC CryptonightR_instruction_mov170 +PUBLIC CryptonightR_instruction_mov171 +PUBLIC CryptonightR_instruction_mov172 +PUBLIC CryptonightR_instruction_mov173 +PUBLIC CryptonightR_instruction_mov174 +PUBLIC CryptonightR_instruction_mov175 +PUBLIC CryptonightR_instruction_mov176 +PUBLIC CryptonightR_instruction_mov177 +PUBLIC CryptonightR_instruction_mov178 +PUBLIC CryptonightR_instruction_mov179 +PUBLIC CryptonightR_instruction_mov180 +PUBLIC CryptonightR_instruction_mov181 +PUBLIC CryptonightR_instruction_mov182 +PUBLIC CryptonightR_instruction_mov183 +PUBLIC CryptonightR_instruction_mov184 +PUBLIC CryptonightR_instruction_mov185 +PUBLIC CryptonightR_instruction_mov186 +PUBLIC CryptonightR_instruction_mov187 +PUBLIC CryptonightR_instruction_mov188 +PUBLIC CryptonightR_instruction_mov189 +PUBLIC CryptonightR_instruction_mov190 +PUBLIC CryptonightR_instruction_mov191 +PUBLIC CryptonightR_instruction_mov192 +PUBLIC CryptonightR_instruction_mov193 +PUBLIC CryptonightR_instruction_mov194 +PUBLIC CryptonightR_instruction_mov195 +PUBLIC CryptonightR_instruction_mov196 +PUBLIC CryptonightR_instruction_mov197 +PUBLIC CryptonightR_instruction_mov198 +PUBLIC CryptonightR_instruction_mov199 +PUBLIC CryptonightR_instruction_mov200 +PUBLIC CryptonightR_instruction_mov201 +PUBLIC CryptonightR_instruction_mov202 +PUBLIC CryptonightR_instruction_mov203 +PUBLIC CryptonightR_instruction_mov204 +PUBLIC CryptonightR_instruction_mov205 +PUBLIC CryptonightR_instruction_mov206 +PUBLIC CryptonightR_instruction_mov207 +PUBLIC CryptonightR_instruction_mov208 +PUBLIC CryptonightR_instruction_mov209 +PUBLIC CryptonightR_instruction_mov210 +PUBLIC CryptonightR_instruction_mov211 +PUBLIC CryptonightR_instruction_mov212 +PUBLIC CryptonightR_instruction_mov213 +PUBLIC CryptonightR_instruction_mov214 +PUBLIC CryptonightR_instruction_mov215 +PUBLIC CryptonightR_instruction_mov216 +PUBLIC CryptonightR_instruction_mov217 +PUBLIC CryptonightR_instruction_mov218 +PUBLIC CryptonightR_instruction_mov219 +PUBLIC CryptonightR_instruction_mov220 +PUBLIC CryptonightR_instruction_mov221 +PUBLIC CryptonightR_instruction_mov222 +PUBLIC CryptonightR_instruction_mov223 +PUBLIC CryptonightR_instruction_mov224 +PUBLIC CryptonightR_instruction_mov225 +PUBLIC CryptonightR_instruction_mov226 +PUBLIC CryptonightR_instruction_mov227 +PUBLIC CryptonightR_instruction_mov228 +PUBLIC CryptonightR_instruction_mov229 +PUBLIC CryptonightR_instruction_mov230 +PUBLIC CryptonightR_instruction_mov231 +PUBLIC CryptonightR_instruction_mov232 +PUBLIC CryptonightR_instruction_mov233 +PUBLIC CryptonightR_instruction_mov234 +PUBLIC CryptonightR_instruction_mov235 +PUBLIC CryptonightR_instruction_mov236 +PUBLIC CryptonightR_instruction_mov237 +PUBLIC CryptonightR_instruction_mov238 +PUBLIC CryptonightR_instruction_mov239 +PUBLIC CryptonightR_instruction_mov240 +PUBLIC CryptonightR_instruction_mov241 +PUBLIC CryptonightR_instruction_mov242 +PUBLIC CryptonightR_instruction_mov243 +PUBLIC CryptonightR_instruction_mov244 +PUBLIC CryptonightR_instruction_mov245 +PUBLIC CryptonightR_instruction_mov246 +PUBLIC CryptonightR_instruction_mov247 +PUBLIC CryptonightR_instruction_mov248 +PUBLIC CryptonightR_instruction_mov249 +PUBLIC CryptonightR_instruction_mov250 +PUBLIC CryptonightR_instruction_mov251 +PUBLIC CryptonightR_instruction_mov252 +PUBLIC CryptonightR_instruction_mov253 +PUBLIC CryptonightR_instruction_mov254 +PUBLIC CryptonightR_instruction_mov255 +PUBLIC CryptonightR_instruction_mov256 + +INCLUDE CryptonightWOW_template_win.inc +INCLUDE CryptonightR_template_win.inc + +CryptonightR_instruction0: + imul rbx, rbx +CryptonightR_instruction1: + imul rbx, rbx +CryptonightR_instruction2: + imul rbx, rbx +CryptonightR_instruction3: + add rbx, r9 + add rbx, 2147483647 +CryptonightR_instruction4: + sub rbx, r9 +CryptonightR_instruction5: + ror ebx, cl +CryptonightR_instruction6: + rol ebx, cl +CryptonightR_instruction7: + xor rbx, r9 +CryptonightR_instruction8: + imul rsi, rbx +CryptonightR_instruction9: + imul rsi, rbx +CryptonightR_instruction10: + imul rsi, rbx +CryptonightR_instruction11: + add rsi, rbx + add rsi, 2147483647 +CryptonightR_instruction12: + sub rsi, rbx +CryptonightR_instruction13: + ror esi, cl +CryptonightR_instruction14: + rol esi, cl +CryptonightR_instruction15: + xor rsi, rbx +CryptonightR_instruction16: + imul rdi, rbx +CryptonightR_instruction17: + imul rdi, rbx +CryptonightR_instruction18: + imul rdi, rbx +CryptonightR_instruction19: + add rdi, rbx + add rdi, 2147483647 +CryptonightR_instruction20: + sub rdi, rbx +CryptonightR_instruction21: + ror edi, cl +CryptonightR_instruction22: + rol edi, cl +CryptonightR_instruction23: + xor rdi, rbx +CryptonightR_instruction24: + imul rbp, rbx +CryptonightR_instruction25: + imul rbp, rbx +CryptonightR_instruction26: + imul rbp, rbx +CryptonightR_instruction27: + add rbp, rbx + add rbp, 2147483647 +CryptonightR_instruction28: + sub rbp, rbx +CryptonightR_instruction29: + ror ebp, cl +CryptonightR_instruction30: + rol ebp, cl +CryptonightR_instruction31: + xor rbp, rbx +CryptonightR_instruction32: + imul rbx, rsi +CryptonightR_instruction33: + imul rbx, rsi +CryptonightR_instruction34: + imul rbx, rsi +CryptonightR_instruction35: + add rbx, rsi + add rbx, 2147483647 +CryptonightR_instruction36: + sub rbx, rsi +CryptonightR_instruction37: + ror ebx, cl +CryptonightR_instruction38: + rol ebx, cl +CryptonightR_instruction39: + xor rbx, rsi +CryptonightR_instruction40: + imul rsi, rsi +CryptonightR_instruction41: + imul rsi, rsi +CryptonightR_instruction42: + imul rsi, rsi +CryptonightR_instruction43: + add rsi, r9 + add rsi, 2147483647 +CryptonightR_instruction44: + sub rsi, r9 +CryptonightR_instruction45: + ror esi, cl +CryptonightR_instruction46: + rol esi, cl +CryptonightR_instruction47: + xor rsi, r9 +CryptonightR_instruction48: + imul rdi, rsi +CryptonightR_instruction49: + imul rdi, rsi +CryptonightR_instruction50: + imul rdi, rsi +CryptonightR_instruction51: + add rdi, rsi + add rdi, 2147483647 +CryptonightR_instruction52: + sub rdi, rsi +CryptonightR_instruction53: + ror edi, cl +CryptonightR_instruction54: + rol edi, cl +CryptonightR_instruction55: + xor rdi, rsi +CryptonightR_instruction56: + imul rbp, rsi +CryptonightR_instruction57: + imul rbp, rsi +CryptonightR_instruction58: + imul rbp, rsi +CryptonightR_instruction59: + add rbp, rsi + add rbp, 2147483647 +CryptonightR_instruction60: + sub rbp, rsi +CryptonightR_instruction61: + ror ebp, cl +CryptonightR_instruction62: + rol ebp, cl +CryptonightR_instruction63: + xor rbp, rsi +CryptonightR_instruction64: + imul rbx, rdi +CryptonightR_instruction65: + imul rbx, rdi +CryptonightR_instruction66: + imul rbx, rdi +CryptonightR_instruction67: + add rbx, rdi + add rbx, 2147483647 +CryptonightR_instruction68: + sub rbx, rdi +CryptonightR_instruction69: + ror ebx, cl +CryptonightR_instruction70: + rol ebx, cl +CryptonightR_instruction71: + xor rbx, rdi +CryptonightR_instruction72: + imul rsi, rdi +CryptonightR_instruction73: + imul rsi, rdi +CryptonightR_instruction74: + imul rsi, rdi +CryptonightR_instruction75: + add rsi, rdi + add rsi, 2147483647 +CryptonightR_instruction76: + sub rsi, rdi +CryptonightR_instruction77: + ror esi, cl +CryptonightR_instruction78: + rol esi, cl +CryptonightR_instruction79: + xor rsi, rdi +CryptonightR_instruction80: + imul rdi, rdi +CryptonightR_instruction81: + imul rdi, rdi +CryptonightR_instruction82: + imul rdi, rdi +CryptonightR_instruction83: + add rdi, r9 + add rdi, 2147483647 +CryptonightR_instruction84: + sub rdi, r9 +CryptonightR_instruction85: + ror edi, cl +CryptonightR_instruction86: + rol edi, cl +CryptonightR_instruction87: + xor rdi, r9 +CryptonightR_instruction88: + imul rbp, rdi +CryptonightR_instruction89: + imul rbp, rdi +CryptonightR_instruction90: + imul rbp, rdi +CryptonightR_instruction91: + add rbp, rdi + add rbp, 2147483647 +CryptonightR_instruction92: + sub rbp, rdi +CryptonightR_instruction93: + ror ebp, cl +CryptonightR_instruction94: + rol ebp, cl +CryptonightR_instruction95: + xor rbp, rdi +CryptonightR_instruction96: + imul rbx, rbp +CryptonightR_instruction97: + imul rbx, rbp +CryptonightR_instruction98: + imul rbx, rbp +CryptonightR_instruction99: + add rbx, rbp + add rbx, 2147483647 +CryptonightR_instruction100: + sub rbx, rbp +CryptonightR_instruction101: + ror ebx, cl +CryptonightR_instruction102: + rol ebx, cl +CryptonightR_instruction103: + xor rbx, rbp +CryptonightR_instruction104: + imul rsi, rbp +CryptonightR_instruction105: + imul rsi, rbp +CryptonightR_instruction106: + imul rsi, rbp +CryptonightR_instruction107: + add rsi, rbp + add rsi, 2147483647 +CryptonightR_instruction108: + sub rsi, rbp +CryptonightR_instruction109: + ror esi, cl +CryptonightR_instruction110: + rol esi, cl +CryptonightR_instruction111: + xor rsi, rbp +CryptonightR_instruction112: + imul rdi, rbp +CryptonightR_instruction113: + imul rdi, rbp +CryptonightR_instruction114: + imul rdi, rbp +CryptonightR_instruction115: + add rdi, rbp + add rdi, 2147483647 +CryptonightR_instruction116: + sub rdi, rbp +CryptonightR_instruction117: + ror edi, cl +CryptonightR_instruction118: + rol edi, cl +CryptonightR_instruction119: + xor rdi, rbp +CryptonightR_instruction120: + imul rbp, rbp +CryptonightR_instruction121: + imul rbp, rbp +CryptonightR_instruction122: + imul rbp, rbp +CryptonightR_instruction123: + add rbp, r9 + add rbp, 2147483647 +CryptonightR_instruction124: + sub rbp, r9 +CryptonightR_instruction125: + ror ebp, cl +CryptonightR_instruction126: + rol ebp, cl +CryptonightR_instruction127: + xor rbp, r9 +CryptonightR_instruction128: + imul rbx, rsp +CryptonightR_instruction129: + imul rbx, rsp +CryptonightR_instruction130: + imul rbx, rsp +CryptonightR_instruction131: + add rbx, rsp + add rbx, 2147483647 +CryptonightR_instruction132: + sub rbx, rsp +CryptonightR_instruction133: + ror ebx, cl +CryptonightR_instruction134: + rol ebx, cl +CryptonightR_instruction135: + xor rbx, rsp +CryptonightR_instruction136: + imul rsi, rsp +CryptonightR_instruction137: + imul rsi, rsp +CryptonightR_instruction138: + imul rsi, rsp +CryptonightR_instruction139: + add rsi, rsp + add rsi, 2147483647 +CryptonightR_instruction140: + sub rsi, rsp +CryptonightR_instruction141: + ror esi, cl +CryptonightR_instruction142: + rol esi, cl +CryptonightR_instruction143: + xor rsi, rsp +CryptonightR_instruction144: + imul rdi, rsp +CryptonightR_instruction145: + imul rdi, rsp +CryptonightR_instruction146: + imul rdi, rsp +CryptonightR_instruction147: + add rdi, rsp + add rdi, 2147483647 +CryptonightR_instruction148: + sub rdi, rsp +CryptonightR_instruction149: + ror edi, cl +CryptonightR_instruction150: + rol edi, cl +CryptonightR_instruction151: + xor rdi, rsp +CryptonightR_instruction152: + imul rbp, rsp +CryptonightR_instruction153: + imul rbp, rsp +CryptonightR_instruction154: + imul rbp, rsp +CryptonightR_instruction155: + add rbp, rsp + add rbp, 2147483647 +CryptonightR_instruction156: + sub rbp, rsp +CryptonightR_instruction157: + ror ebp, cl +CryptonightR_instruction158: + rol ebp, cl +CryptonightR_instruction159: + xor rbp, rsp +CryptonightR_instruction160: + imul rbx, r15 +CryptonightR_instruction161: + imul rbx, r15 +CryptonightR_instruction162: + imul rbx, r15 +CryptonightR_instruction163: + add rbx, r15 + add rbx, 2147483647 +CryptonightR_instruction164: + sub rbx, r15 +CryptonightR_instruction165: + ror ebx, cl +CryptonightR_instruction166: + rol ebx, cl +CryptonightR_instruction167: + xor rbx, r15 +CryptonightR_instruction168: + imul rsi, r15 +CryptonightR_instruction169: + imul rsi, r15 +CryptonightR_instruction170: + imul rsi, r15 +CryptonightR_instruction171: + add rsi, r15 + add rsi, 2147483647 +CryptonightR_instruction172: + sub rsi, r15 +CryptonightR_instruction173: + ror esi, cl +CryptonightR_instruction174: + rol esi, cl +CryptonightR_instruction175: + xor rsi, r15 +CryptonightR_instruction176: + imul rdi, r15 +CryptonightR_instruction177: + imul rdi, r15 +CryptonightR_instruction178: + imul rdi, r15 +CryptonightR_instruction179: + add rdi, r15 + add rdi, 2147483647 +CryptonightR_instruction180: + sub rdi, r15 +CryptonightR_instruction181: + ror edi, cl +CryptonightR_instruction182: + rol edi, cl +CryptonightR_instruction183: + xor rdi, r15 +CryptonightR_instruction184: + imul rbp, r15 +CryptonightR_instruction185: + imul rbp, r15 +CryptonightR_instruction186: + imul rbp, r15 +CryptonightR_instruction187: + add rbp, r15 + add rbp, 2147483647 +CryptonightR_instruction188: + sub rbp, r15 +CryptonightR_instruction189: + ror ebp, cl +CryptonightR_instruction190: + rol ebp, cl +CryptonightR_instruction191: + xor rbp, r15 +CryptonightR_instruction192: + imul rbx, rax +CryptonightR_instruction193: + imul rbx, rax +CryptonightR_instruction194: + imul rbx, rax +CryptonightR_instruction195: + add rbx, rax + add rbx, 2147483647 +CryptonightR_instruction196: + sub rbx, rax +CryptonightR_instruction197: + ror ebx, cl +CryptonightR_instruction198: + rol ebx, cl +CryptonightR_instruction199: + xor rbx, rax +CryptonightR_instruction200: + imul rsi, rax +CryptonightR_instruction201: + imul rsi, rax +CryptonightR_instruction202: + imul rsi, rax +CryptonightR_instruction203: + add rsi, rax + add rsi, 2147483647 +CryptonightR_instruction204: + sub rsi, rax +CryptonightR_instruction205: + ror esi, cl +CryptonightR_instruction206: + rol esi, cl +CryptonightR_instruction207: + xor rsi, rax +CryptonightR_instruction208: + imul rdi, rax +CryptonightR_instruction209: + imul rdi, rax +CryptonightR_instruction210: + imul rdi, rax +CryptonightR_instruction211: + add rdi, rax + add rdi, 2147483647 +CryptonightR_instruction212: + sub rdi, rax +CryptonightR_instruction213: + ror edi, cl +CryptonightR_instruction214: + rol edi, cl +CryptonightR_instruction215: + xor rdi, rax +CryptonightR_instruction216: + imul rbp, rax +CryptonightR_instruction217: + imul rbp, rax +CryptonightR_instruction218: + imul rbp, rax +CryptonightR_instruction219: + add rbp, rax + add rbp, 2147483647 +CryptonightR_instruction220: + sub rbp, rax +CryptonightR_instruction221: + ror ebp, cl +CryptonightR_instruction222: + rol ebp, cl +CryptonightR_instruction223: + xor rbp, rax +CryptonightR_instruction224: + imul rbx, rdx +CryptonightR_instruction225: + imul rbx, rdx +CryptonightR_instruction226: + imul rbx, rdx +CryptonightR_instruction227: + add rbx, rdx + add rbx, 2147483647 +CryptonightR_instruction228: + sub rbx, rdx +CryptonightR_instruction229: + ror ebx, cl +CryptonightR_instruction230: + rol ebx, cl +CryptonightR_instruction231: + xor rbx, rdx +CryptonightR_instruction232: + imul rsi, rdx +CryptonightR_instruction233: + imul rsi, rdx +CryptonightR_instruction234: + imul rsi, rdx +CryptonightR_instruction235: + add rsi, rdx + add rsi, 2147483647 +CryptonightR_instruction236: + sub rsi, rdx +CryptonightR_instruction237: + ror esi, cl +CryptonightR_instruction238: + rol esi, cl +CryptonightR_instruction239: + xor rsi, rdx +CryptonightR_instruction240: + imul rdi, rdx +CryptonightR_instruction241: + imul rdi, rdx +CryptonightR_instruction242: + imul rdi, rdx +CryptonightR_instruction243: + add rdi, rdx + add rdi, 2147483647 +CryptonightR_instruction244: + sub rdi, rdx +CryptonightR_instruction245: + ror edi, cl +CryptonightR_instruction246: + rol edi, cl +CryptonightR_instruction247: + xor rdi, rdx +CryptonightR_instruction248: + imul rbp, rdx +CryptonightR_instruction249: + imul rbp, rdx +CryptonightR_instruction250: + imul rbp, rdx +CryptonightR_instruction251: + add rbp, rdx + add rbp, 2147483647 +CryptonightR_instruction252: + sub rbp, rdx +CryptonightR_instruction253: + ror ebp, cl +CryptonightR_instruction254: + rol ebp, cl +CryptonightR_instruction255: + xor rbp, rdx +CryptonightR_instruction256: + imul rbx, rbx +CryptonightR_instruction_mov0: + +CryptonightR_instruction_mov1: + +CryptonightR_instruction_mov2: + +CryptonightR_instruction_mov3: + +CryptonightR_instruction_mov4: + +CryptonightR_instruction_mov5: + mov rcx, rbx +CryptonightR_instruction_mov6: + mov rcx, rbx +CryptonightR_instruction_mov7: + +CryptonightR_instruction_mov8: + +CryptonightR_instruction_mov9: + +CryptonightR_instruction_mov10: + +CryptonightR_instruction_mov11: + +CryptonightR_instruction_mov12: + +CryptonightR_instruction_mov13: + mov rcx, rbx +CryptonightR_instruction_mov14: + mov rcx, rbx +CryptonightR_instruction_mov15: + +CryptonightR_instruction_mov16: + +CryptonightR_instruction_mov17: + +CryptonightR_instruction_mov18: + +CryptonightR_instruction_mov19: + +CryptonightR_instruction_mov20: + +CryptonightR_instruction_mov21: + mov rcx, rbx +CryptonightR_instruction_mov22: + mov rcx, rbx +CryptonightR_instruction_mov23: + +CryptonightR_instruction_mov24: + +CryptonightR_instruction_mov25: + +CryptonightR_instruction_mov26: + +CryptonightR_instruction_mov27: + +CryptonightR_instruction_mov28: + +CryptonightR_instruction_mov29: + mov rcx, rbx +CryptonightR_instruction_mov30: + mov rcx, rbx +CryptonightR_instruction_mov31: + +CryptonightR_instruction_mov32: + +CryptonightR_instruction_mov33: + +CryptonightR_instruction_mov34: + +CryptonightR_instruction_mov35: + +CryptonightR_instruction_mov36: + +CryptonightR_instruction_mov37: + mov rcx, rsi +CryptonightR_instruction_mov38: + mov rcx, rsi +CryptonightR_instruction_mov39: + +CryptonightR_instruction_mov40: + +CryptonightR_instruction_mov41: + +CryptonightR_instruction_mov42: + +CryptonightR_instruction_mov43: + +CryptonightR_instruction_mov44: + +CryptonightR_instruction_mov45: + mov rcx, rsi +CryptonightR_instruction_mov46: + mov rcx, rsi +CryptonightR_instruction_mov47: + +CryptonightR_instruction_mov48: + +CryptonightR_instruction_mov49: + +CryptonightR_instruction_mov50: + +CryptonightR_instruction_mov51: + +CryptonightR_instruction_mov52: + +CryptonightR_instruction_mov53: + mov rcx, rsi +CryptonightR_instruction_mov54: + mov rcx, rsi +CryptonightR_instruction_mov55: + +CryptonightR_instruction_mov56: + +CryptonightR_instruction_mov57: + +CryptonightR_instruction_mov58: + +CryptonightR_instruction_mov59: + +CryptonightR_instruction_mov60: + +CryptonightR_instruction_mov61: + mov rcx, rsi +CryptonightR_instruction_mov62: + mov rcx, rsi +CryptonightR_instruction_mov63: + +CryptonightR_instruction_mov64: + +CryptonightR_instruction_mov65: + +CryptonightR_instruction_mov66: + +CryptonightR_instruction_mov67: + +CryptonightR_instruction_mov68: + +CryptonightR_instruction_mov69: + mov rcx, rdi +CryptonightR_instruction_mov70: + mov rcx, rdi +CryptonightR_instruction_mov71: + +CryptonightR_instruction_mov72: + +CryptonightR_instruction_mov73: + +CryptonightR_instruction_mov74: + +CryptonightR_instruction_mov75: + +CryptonightR_instruction_mov76: + +CryptonightR_instruction_mov77: + mov rcx, rdi +CryptonightR_instruction_mov78: + mov rcx, rdi +CryptonightR_instruction_mov79: + +CryptonightR_instruction_mov80: + +CryptonightR_instruction_mov81: + +CryptonightR_instruction_mov82: + +CryptonightR_instruction_mov83: + +CryptonightR_instruction_mov84: + +CryptonightR_instruction_mov85: + mov rcx, rdi +CryptonightR_instruction_mov86: + mov rcx, rdi +CryptonightR_instruction_mov87: + +CryptonightR_instruction_mov88: + +CryptonightR_instruction_mov89: + +CryptonightR_instruction_mov90: + +CryptonightR_instruction_mov91: + +CryptonightR_instruction_mov92: + +CryptonightR_instruction_mov93: + mov rcx, rdi +CryptonightR_instruction_mov94: + mov rcx, rdi +CryptonightR_instruction_mov95: + +CryptonightR_instruction_mov96: + +CryptonightR_instruction_mov97: + +CryptonightR_instruction_mov98: + +CryptonightR_instruction_mov99: + +CryptonightR_instruction_mov100: + +CryptonightR_instruction_mov101: + mov rcx, rbp +CryptonightR_instruction_mov102: + mov rcx, rbp +CryptonightR_instruction_mov103: + +CryptonightR_instruction_mov104: + +CryptonightR_instruction_mov105: + +CryptonightR_instruction_mov106: + +CryptonightR_instruction_mov107: + +CryptonightR_instruction_mov108: + +CryptonightR_instruction_mov109: + mov rcx, rbp +CryptonightR_instruction_mov110: + mov rcx, rbp +CryptonightR_instruction_mov111: + +CryptonightR_instruction_mov112: + +CryptonightR_instruction_mov113: + +CryptonightR_instruction_mov114: + +CryptonightR_instruction_mov115: + +CryptonightR_instruction_mov116: + +CryptonightR_instruction_mov117: + mov rcx, rbp +CryptonightR_instruction_mov118: + mov rcx, rbp +CryptonightR_instruction_mov119: + +CryptonightR_instruction_mov120: + +CryptonightR_instruction_mov121: + +CryptonightR_instruction_mov122: + +CryptonightR_instruction_mov123: + +CryptonightR_instruction_mov124: + +CryptonightR_instruction_mov125: + mov rcx, rbp +CryptonightR_instruction_mov126: + mov rcx, rbp +CryptonightR_instruction_mov127: + +CryptonightR_instruction_mov128: + +CryptonightR_instruction_mov129: + +CryptonightR_instruction_mov130: + +CryptonightR_instruction_mov131: + +CryptonightR_instruction_mov132: + +CryptonightR_instruction_mov133: + mov rcx, rsp +CryptonightR_instruction_mov134: + mov rcx, rsp +CryptonightR_instruction_mov135: + +CryptonightR_instruction_mov136: + +CryptonightR_instruction_mov137: + +CryptonightR_instruction_mov138: + +CryptonightR_instruction_mov139: + +CryptonightR_instruction_mov140: + +CryptonightR_instruction_mov141: + mov rcx, rsp +CryptonightR_instruction_mov142: + mov rcx, rsp +CryptonightR_instruction_mov143: + +CryptonightR_instruction_mov144: + +CryptonightR_instruction_mov145: + +CryptonightR_instruction_mov146: + +CryptonightR_instruction_mov147: + +CryptonightR_instruction_mov148: + +CryptonightR_instruction_mov149: + mov rcx, rsp +CryptonightR_instruction_mov150: + mov rcx, rsp +CryptonightR_instruction_mov151: + +CryptonightR_instruction_mov152: + +CryptonightR_instruction_mov153: + +CryptonightR_instruction_mov154: + +CryptonightR_instruction_mov155: + +CryptonightR_instruction_mov156: + +CryptonightR_instruction_mov157: + mov rcx, rsp +CryptonightR_instruction_mov158: + mov rcx, rsp +CryptonightR_instruction_mov159: + +CryptonightR_instruction_mov160: + +CryptonightR_instruction_mov161: + +CryptonightR_instruction_mov162: + +CryptonightR_instruction_mov163: + +CryptonightR_instruction_mov164: + +CryptonightR_instruction_mov165: + mov rcx, r15 +CryptonightR_instruction_mov166: + mov rcx, r15 +CryptonightR_instruction_mov167: + +CryptonightR_instruction_mov168: + +CryptonightR_instruction_mov169: + +CryptonightR_instruction_mov170: + +CryptonightR_instruction_mov171: + +CryptonightR_instruction_mov172: + +CryptonightR_instruction_mov173: + mov rcx, r15 +CryptonightR_instruction_mov174: + mov rcx, r15 +CryptonightR_instruction_mov175: + +CryptonightR_instruction_mov176: + +CryptonightR_instruction_mov177: + +CryptonightR_instruction_mov178: + +CryptonightR_instruction_mov179: + +CryptonightR_instruction_mov180: + +CryptonightR_instruction_mov181: + mov rcx, r15 +CryptonightR_instruction_mov182: + mov rcx, r15 +CryptonightR_instruction_mov183: + +CryptonightR_instruction_mov184: + +CryptonightR_instruction_mov185: + +CryptonightR_instruction_mov186: + +CryptonightR_instruction_mov187: + +CryptonightR_instruction_mov188: + +CryptonightR_instruction_mov189: + mov rcx, r15 +CryptonightR_instruction_mov190: + mov rcx, r15 +CryptonightR_instruction_mov191: + +CryptonightR_instruction_mov192: + +CryptonightR_instruction_mov193: + +CryptonightR_instruction_mov194: + +CryptonightR_instruction_mov195: + +CryptonightR_instruction_mov196: + +CryptonightR_instruction_mov197: + mov rcx, rax +CryptonightR_instruction_mov198: + mov rcx, rax +CryptonightR_instruction_mov199: + +CryptonightR_instruction_mov200: + +CryptonightR_instruction_mov201: + +CryptonightR_instruction_mov202: + +CryptonightR_instruction_mov203: + +CryptonightR_instruction_mov204: + +CryptonightR_instruction_mov205: + mov rcx, rax +CryptonightR_instruction_mov206: + mov rcx, rax +CryptonightR_instruction_mov207: + +CryptonightR_instruction_mov208: + +CryptonightR_instruction_mov209: + +CryptonightR_instruction_mov210: + +CryptonightR_instruction_mov211: + +CryptonightR_instruction_mov212: + +CryptonightR_instruction_mov213: + mov rcx, rax +CryptonightR_instruction_mov214: + mov rcx, rax +CryptonightR_instruction_mov215: + +CryptonightR_instruction_mov216: + +CryptonightR_instruction_mov217: + +CryptonightR_instruction_mov218: + +CryptonightR_instruction_mov219: + +CryptonightR_instruction_mov220: + +CryptonightR_instruction_mov221: + mov rcx, rax +CryptonightR_instruction_mov222: + mov rcx, rax +CryptonightR_instruction_mov223: + +CryptonightR_instruction_mov224: + +CryptonightR_instruction_mov225: + +CryptonightR_instruction_mov226: + +CryptonightR_instruction_mov227: + +CryptonightR_instruction_mov228: + +CryptonightR_instruction_mov229: + mov rcx, rdx +CryptonightR_instruction_mov230: + mov rcx, rdx +CryptonightR_instruction_mov231: + +CryptonightR_instruction_mov232: + +CryptonightR_instruction_mov233: + +CryptonightR_instruction_mov234: + +CryptonightR_instruction_mov235: + +CryptonightR_instruction_mov236: + +CryptonightR_instruction_mov237: + mov rcx, rdx +CryptonightR_instruction_mov238: + mov rcx, rdx +CryptonightR_instruction_mov239: + +CryptonightR_instruction_mov240: + +CryptonightR_instruction_mov241: + +CryptonightR_instruction_mov242: + +CryptonightR_instruction_mov243: + +CryptonightR_instruction_mov244: + +CryptonightR_instruction_mov245: + mov rcx, rdx +CryptonightR_instruction_mov246: + mov rcx, rdx +CryptonightR_instruction_mov247: + +CryptonightR_instruction_mov248: + +CryptonightR_instruction_mov249: + +CryptonightR_instruction_mov250: + +CryptonightR_instruction_mov251: + +CryptonightR_instruction_mov252: + +CryptonightR_instruction_mov253: + mov rcx, rdx +CryptonightR_instruction_mov254: + mov rcx, rdx +CryptonightR_instruction_mov255: + +CryptonightR_instruction_mov256: + +_TEXT_CN_TEMPLATE ENDS +END diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.h b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.h new file mode 100644 index 000000000..c2054705b --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.h @@ -0,0 +1,1063 @@ +// Auto-generated file, do not edit + +extern "C" +{ + void CryptonightWOW_template_part1(); + void CryptonightWOW_template_mainloop(); + void CryptonightWOW_template_part2(); + void CryptonightWOW_template_part3(); + void CryptonightWOW_template_end(); + void CryptonightWOW_template_double_part1(); + void CryptonightWOW_template_double_mainloop(); + void CryptonightWOW_template_double_part2(); + void CryptonightWOW_template_double_part3(); + void CryptonightWOW_template_double_part4(); + void CryptonightWOW_template_double_end(); + + void CryptonightR_template_part1(); + void CryptonightR_template_mainloop(); + void CryptonightR_template_part2(); + void CryptonightR_template_part3(); + void CryptonightR_template_end(); + void CryptonightR_template_double_part1(); + void CryptonightR_template_double_mainloop(); + void CryptonightR_template_double_part2(); + void CryptonightR_template_double_part3(); + void CryptonightR_template_double_part4(); + void CryptonightR_template_double_end(); + + void CryptonightR_instruction0(); + void CryptonightR_instruction1(); + void CryptonightR_instruction2(); + void CryptonightR_instruction3(); + void CryptonightR_instruction4(); + void CryptonightR_instruction5(); + void CryptonightR_instruction6(); + void CryptonightR_instruction7(); + void CryptonightR_instruction8(); + void CryptonightR_instruction9(); + void CryptonightR_instruction10(); + void CryptonightR_instruction11(); + void CryptonightR_instruction12(); + void CryptonightR_instruction13(); + void CryptonightR_instruction14(); + void CryptonightR_instruction15(); + void CryptonightR_instruction16(); + void CryptonightR_instruction17(); + void CryptonightR_instruction18(); + void CryptonightR_instruction19(); + void CryptonightR_instruction20(); + void CryptonightR_instruction21(); + void CryptonightR_instruction22(); + void CryptonightR_instruction23(); + void CryptonightR_instruction24(); + void CryptonightR_instruction25(); + void CryptonightR_instruction26(); + void CryptonightR_instruction27(); + void CryptonightR_instruction28(); + void CryptonightR_instruction29(); + void CryptonightR_instruction30(); + void CryptonightR_instruction31(); + void CryptonightR_instruction32(); + void CryptonightR_instruction33(); + void CryptonightR_instruction34(); + void CryptonightR_instruction35(); + void CryptonightR_instruction36(); + void CryptonightR_instruction37(); + void CryptonightR_instruction38(); + void CryptonightR_instruction39(); + void CryptonightR_instruction40(); + void CryptonightR_instruction41(); + void CryptonightR_instruction42(); + void CryptonightR_instruction43(); + void CryptonightR_instruction44(); + void CryptonightR_instruction45(); + void CryptonightR_instruction46(); + void CryptonightR_instruction47(); + void CryptonightR_instruction48(); + void CryptonightR_instruction49(); + void CryptonightR_instruction50(); + void CryptonightR_instruction51(); + void CryptonightR_instruction52(); + void CryptonightR_instruction53(); + void CryptonightR_instruction54(); + void CryptonightR_instruction55(); + void CryptonightR_instruction56(); + void CryptonightR_instruction57(); + void CryptonightR_instruction58(); + void CryptonightR_instruction59(); + void CryptonightR_instruction60(); + void CryptonightR_instruction61(); + void CryptonightR_instruction62(); + void CryptonightR_instruction63(); + void CryptonightR_instruction64(); + void CryptonightR_instruction65(); + void CryptonightR_instruction66(); + void CryptonightR_instruction67(); + void CryptonightR_instruction68(); + void CryptonightR_instruction69(); + void CryptonightR_instruction70(); + void CryptonightR_instruction71(); + void CryptonightR_instruction72(); + void CryptonightR_instruction73(); + void CryptonightR_instruction74(); + void CryptonightR_instruction75(); + void CryptonightR_instruction76(); + void CryptonightR_instruction77(); + void CryptonightR_instruction78(); + void CryptonightR_instruction79(); + void CryptonightR_instruction80(); + void CryptonightR_instruction81(); + void CryptonightR_instruction82(); + void CryptonightR_instruction83(); + void CryptonightR_instruction84(); + void CryptonightR_instruction85(); + void CryptonightR_instruction86(); + void CryptonightR_instruction87(); + void CryptonightR_instruction88(); + void CryptonightR_instruction89(); + void CryptonightR_instruction90(); + void CryptonightR_instruction91(); + void CryptonightR_instruction92(); + void CryptonightR_instruction93(); + void CryptonightR_instruction94(); + void CryptonightR_instruction95(); + void CryptonightR_instruction96(); + void CryptonightR_instruction97(); + void CryptonightR_instruction98(); + void CryptonightR_instruction99(); + void CryptonightR_instruction100(); + void CryptonightR_instruction101(); + void CryptonightR_instruction102(); + void CryptonightR_instruction103(); + void CryptonightR_instruction104(); + void CryptonightR_instruction105(); + void CryptonightR_instruction106(); + void CryptonightR_instruction107(); + void CryptonightR_instruction108(); + void CryptonightR_instruction109(); + void CryptonightR_instruction110(); + void CryptonightR_instruction111(); + void CryptonightR_instruction112(); + void CryptonightR_instruction113(); + void CryptonightR_instruction114(); + void CryptonightR_instruction115(); + void CryptonightR_instruction116(); + void CryptonightR_instruction117(); + void CryptonightR_instruction118(); + void CryptonightR_instruction119(); + void CryptonightR_instruction120(); + void CryptonightR_instruction121(); + void CryptonightR_instruction122(); + void CryptonightR_instruction123(); + void CryptonightR_instruction124(); + void CryptonightR_instruction125(); + void CryptonightR_instruction126(); + void CryptonightR_instruction127(); + void CryptonightR_instruction128(); + void CryptonightR_instruction129(); + void CryptonightR_instruction130(); + void CryptonightR_instruction131(); + void CryptonightR_instruction132(); + void CryptonightR_instruction133(); + void CryptonightR_instruction134(); + void CryptonightR_instruction135(); + void CryptonightR_instruction136(); + void CryptonightR_instruction137(); + void CryptonightR_instruction138(); + void CryptonightR_instruction139(); + void CryptonightR_instruction140(); + void CryptonightR_instruction141(); + void CryptonightR_instruction142(); + void CryptonightR_instruction143(); + void CryptonightR_instruction144(); + void CryptonightR_instruction145(); + void CryptonightR_instruction146(); + void CryptonightR_instruction147(); + void CryptonightR_instruction148(); + void CryptonightR_instruction149(); + void CryptonightR_instruction150(); + void CryptonightR_instruction151(); + void CryptonightR_instruction152(); + void CryptonightR_instruction153(); + void CryptonightR_instruction154(); + void CryptonightR_instruction155(); + void CryptonightR_instruction156(); + void CryptonightR_instruction157(); + void CryptonightR_instruction158(); + void CryptonightR_instruction159(); + void CryptonightR_instruction160(); + void CryptonightR_instruction161(); + void CryptonightR_instruction162(); + void CryptonightR_instruction163(); + void CryptonightR_instruction164(); + void CryptonightR_instruction165(); + void CryptonightR_instruction166(); + void CryptonightR_instruction167(); + void CryptonightR_instruction168(); + void CryptonightR_instruction169(); + void CryptonightR_instruction170(); + void CryptonightR_instruction171(); + void CryptonightR_instruction172(); + void CryptonightR_instruction173(); + void CryptonightR_instruction174(); + void CryptonightR_instruction175(); + void CryptonightR_instruction176(); + void CryptonightR_instruction177(); + void CryptonightR_instruction178(); + void CryptonightR_instruction179(); + void CryptonightR_instruction180(); + void CryptonightR_instruction181(); + void CryptonightR_instruction182(); + void CryptonightR_instruction183(); + void CryptonightR_instruction184(); + void CryptonightR_instruction185(); + void CryptonightR_instruction186(); + void CryptonightR_instruction187(); + void CryptonightR_instruction188(); + void CryptonightR_instruction189(); + void CryptonightR_instruction190(); + void CryptonightR_instruction191(); + void CryptonightR_instruction192(); + void CryptonightR_instruction193(); + void CryptonightR_instruction194(); + void CryptonightR_instruction195(); + void CryptonightR_instruction196(); + void CryptonightR_instruction197(); + void CryptonightR_instruction198(); + void CryptonightR_instruction199(); + void CryptonightR_instruction200(); + void CryptonightR_instruction201(); + void CryptonightR_instruction202(); + void CryptonightR_instruction203(); + void CryptonightR_instruction204(); + void CryptonightR_instruction205(); + void CryptonightR_instruction206(); + void CryptonightR_instruction207(); + void CryptonightR_instruction208(); + void CryptonightR_instruction209(); + void CryptonightR_instruction210(); + void CryptonightR_instruction211(); + void CryptonightR_instruction212(); + void CryptonightR_instruction213(); + void CryptonightR_instruction214(); + void CryptonightR_instruction215(); + void CryptonightR_instruction216(); + void CryptonightR_instruction217(); + void CryptonightR_instruction218(); + void CryptonightR_instruction219(); + void CryptonightR_instruction220(); + void CryptonightR_instruction221(); + void CryptonightR_instruction222(); + void CryptonightR_instruction223(); + void CryptonightR_instruction224(); + void CryptonightR_instruction225(); + void CryptonightR_instruction226(); + void CryptonightR_instruction227(); + void CryptonightR_instruction228(); + void CryptonightR_instruction229(); + void CryptonightR_instruction230(); + void CryptonightR_instruction231(); + void CryptonightR_instruction232(); + void CryptonightR_instruction233(); + void CryptonightR_instruction234(); + void CryptonightR_instruction235(); + void CryptonightR_instruction236(); + void CryptonightR_instruction237(); + void CryptonightR_instruction238(); + void CryptonightR_instruction239(); + void CryptonightR_instruction240(); + void CryptonightR_instruction241(); + void CryptonightR_instruction242(); + void CryptonightR_instruction243(); + void CryptonightR_instruction244(); + void CryptonightR_instruction245(); + void CryptonightR_instruction246(); + void CryptonightR_instruction247(); + void CryptonightR_instruction248(); + void CryptonightR_instruction249(); + void CryptonightR_instruction250(); + void CryptonightR_instruction251(); + void CryptonightR_instruction252(); + void CryptonightR_instruction253(); + void CryptonightR_instruction254(); + void CryptonightR_instruction255(); + void CryptonightR_instruction256(); + void CryptonightR_instruction_mov0(); + void CryptonightR_instruction_mov1(); + void CryptonightR_instruction_mov2(); + void CryptonightR_instruction_mov3(); + void CryptonightR_instruction_mov4(); + void CryptonightR_instruction_mov5(); + void CryptonightR_instruction_mov6(); + void CryptonightR_instruction_mov7(); + void CryptonightR_instruction_mov8(); + void CryptonightR_instruction_mov9(); + void CryptonightR_instruction_mov10(); + void CryptonightR_instruction_mov11(); + void CryptonightR_instruction_mov12(); + void CryptonightR_instruction_mov13(); + void CryptonightR_instruction_mov14(); + void CryptonightR_instruction_mov15(); + void CryptonightR_instruction_mov16(); + void CryptonightR_instruction_mov17(); + void CryptonightR_instruction_mov18(); + void CryptonightR_instruction_mov19(); + void CryptonightR_instruction_mov20(); + void CryptonightR_instruction_mov21(); + void CryptonightR_instruction_mov22(); + void CryptonightR_instruction_mov23(); + void CryptonightR_instruction_mov24(); + void CryptonightR_instruction_mov25(); + void CryptonightR_instruction_mov26(); + void CryptonightR_instruction_mov27(); + void CryptonightR_instruction_mov28(); + void CryptonightR_instruction_mov29(); + void CryptonightR_instruction_mov30(); + void CryptonightR_instruction_mov31(); + void CryptonightR_instruction_mov32(); + void CryptonightR_instruction_mov33(); + void CryptonightR_instruction_mov34(); + void CryptonightR_instruction_mov35(); + void CryptonightR_instruction_mov36(); + void CryptonightR_instruction_mov37(); + void CryptonightR_instruction_mov38(); + void CryptonightR_instruction_mov39(); + void CryptonightR_instruction_mov40(); + void CryptonightR_instruction_mov41(); + void CryptonightR_instruction_mov42(); + void CryptonightR_instruction_mov43(); + void CryptonightR_instruction_mov44(); + void CryptonightR_instruction_mov45(); + void CryptonightR_instruction_mov46(); + void CryptonightR_instruction_mov47(); + void CryptonightR_instruction_mov48(); + void CryptonightR_instruction_mov49(); + void CryptonightR_instruction_mov50(); + void CryptonightR_instruction_mov51(); + void CryptonightR_instruction_mov52(); + void CryptonightR_instruction_mov53(); + void CryptonightR_instruction_mov54(); + void CryptonightR_instruction_mov55(); + void CryptonightR_instruction_mov56(); + void CryptonightR_instruction_mov57(); + void CryptonightR_instruction_mov58(); + void CryptonightR_instruction_mov59(); + void CryptonightR_instruction_mov60(); + void CryptonightR_instruction_mov61(); + void CryptonightR_instruction_mov62(); + void CryptonightR_instruction_mov63(); + void CryptonightR_instruction_mov64(); + void CryptonightR_instruction_mov65(); + void CryptonightR_instruction_mov66(); + void CryptonightR_instruction_mov67(); + void CryptonightR_instruction_mov68(); + void CryptonightR_instruction_mov69(); + void CryptonightR_instruction_mov70(); + void CryptonightR_instruction_mov71(); + void CryptonightR_instruction_mov72(); + void CryptonightR_instruction_mov73(); + void CryptonightR_instruction_mov74(); + void CryptonightR_instruction_mov75(); + void CryptonightR_instruction_mov76(); + void CryptonightR_instruction_mov77(); + void CryptonightR_instruction_mov78(); + void CryptonightR_instruction_mov79(); + void CryptonightR_instruction_mov80(); + void CryptonightR_instruction_mov81(); + void CryptonightR_instruction_mov82(); + void CryptonightR_instruction_mov83(); + void CryptonightR_instruction_mov84(); + void CryptonightR_instruction_mov85(); + void CryptonightR_instruction_mov86(); + void CryptonightR_instruction_mov87(); + void CryptonightR_instruction_mov88(); + void CryptonightR_instruction_mov89(); + void CryptonightR_instruction_mov90(); + void CryptonightR_instruction_mov91(); + void CryptonightR_instruction_mov92(); + void CryptonightR_instruction_mov93(); + void CryptonightR_instruction_mov94(); + void CryptonightR_instruction_mov95(); + void CryptonightR_instruction_mov96(); + void CryptonightR_instruction_mov97(); + void CryptonightR_instruction_mov98(); + void CryptonightR_instruction_mov99(); + void CryptonightR_instruction_mov100(); + void CryptonightR_instruction_mov101(); + void CryptonightR_instruction_mov102(); + void CryptonightR_instruction_mov103(); + void CryptonightR_instruction_mov104(); + void CryptonightR_instruction_mov105(); + void CryptonightR_instruction_mov106(); + void CryptonightR_instruction_mov107(); + void CryptonightR_instruction_mov108(); + void CryptonightR_instruction_mov109(); + void CryptonightR_instruction_mov110(); + void CryptonightR_instruction_mov111(); + void CryptonightR_instruction_mov112(); + void CryptonightR_instruction_mov113(); + void CryptonightR_instruction_mov114(); + void CryptonightR_instruction_mov115(); + void CryptonightR_instruction_mov116(); + void CryptonightR_instruction_mov117(); + void CryptonightR_instruction_mov118(); + void CryptonightR_instruction_mov119(); + void CryptonightR_instruction_mov120(); + void CryptonightR_instruction_mov121(); + void CryptonightR_instruction_mov122(); + void CryptonightR_instruction_mov123(); + void CryptonightR_instruction_mov124(); + void CryptonightR_instruction_mov125(); + void CryptonightR_instruction_mov126(); + void CryptonightR_instruction_mov127(); + void CryptonightR_instruction_mov128(); + void CryptonightR_instruction_mov129(); + void CryptonightR_instruction_mov130(); + void CryptonightR_instruction_mov131(); + void CryptonightR_instruction_mov132(); + void CryptonightR_instruction_mov133(); + void CryptonightR_instruction_mov134(); + void CryptonightR_instruction_mov135(); + void CryptonightR_instruction_mov136(); + void CryptonightR_instruction_mov137(); + void CryptonightR_instruction_mov138(); + void CryptonightR_instruction_mov139(); + void CryptonightR_instruction_mov140(); + void CryptonightR_instruction_mov141(); + void CryptonightR_instruction_mov142(); + void CryptonightR_instruction_mov143(); + void CryptonightR_instruction_mov144(); + void CryptonightR_instruction_mov145(); + void CryptonightR_instruction_mov146(); + void CryptonightR_instruction_mov147(); + void CryptonightR_instruction_mov148(); + void CryptonightR_instruction_mov149(); + void CryptonightR_instruction_mov150(); + void CryptonightR_instruction_mov151(); + void CryptonightR_instruction_mov152(); + void CryptonightR_instruction_mov153(); + void CryptonightR_instruction_mov154(); + void CryptonightR_instruction_mov155(); + void CryptonightR_instruction_mov156(); + void CryptonightR_instruction_mov157(); + void CryptonightR_instruction_mov158(); + void CryptonightR_instruction_mov159(); + void CryptonightR_instruction_mov160(); + void CryptonightR_instruction_mov161(); + void CryptonightR_instruction_mov162(); + void CryptonightR_instruction_mov163(); + void CryptonightR_instruction_mov164(); + void CryptonightR_instruction_mov165(); + void CryptonightR_instruction_mov166(); + void CryptonightR_instruction_mov167(); + void CryptonightR_instruction_mov168(); + void CryptonightR_instruction_mov169(); + void CryptonightR_instruction_mov170(); + void CryptonightR_instruction_mov171(); + void CryptonightR_instruction_mov172(); + void CryptonightR_instruction_mov173(); + void CryptonightR_instruction_mov174(); + void CryptonightR_instruction_mov175(); + void CryptonightR_instruction_mov176(); + void CryptonightR_instruction_mov177(); + void CryptonightR_instruction_mov178(); + void CryptonightR_instruction_mov179(); + void CryptonightR_instruction_mov180(); + void CryptonightR_instruction_mov181(); + void CryptonightR_instruction_mov182(); + void CryptonightR_instruction_mov183(); + void CryptonightR_instruction_mov184(); + void CryptonightR_instruction_mov185(); + void CryptonightR_instruction_mov186(); + void CryptonightR_instruction_mov187(); + void CryptonightR_instruction_mov188(); + void CryptonightR_instruction_mov189(); + void CryptonightR_instruction_mov190(); + void CryptonightR_instruction_mov191(); + void CryptonightR_instruction_mov192(); + void CryptonightR_instruction_mov193(); + void CryptonightR_instruction_mov194(); + void CryptonightR_instruction_mov195(); + void CryptonightR_instruction_mov196(); + void CryptonightR_instruction_mov197(); + void CryptonightR_instruction_mov198(); + void CryptonightR_instruction_mov199(); + void CryptonightR_instruction_mov200(); + void CryptonightR_instruction_mov201(); + void CryptonightR_instruction_mov202(); + void CryptonightR_instruction_mov203(); + void CryptonightR_instruction_mov204(); + void CryptonightR_instruction_mov205(); + void CryptonightR_instruction_mov206(); + void CryptonightR_instruction_mov207(); + void CryptonightR_instruction_mov208(); + void CryptonightR_instruction_mov209(); + void CryptonightR_instruction_mov210(); + void CryptonightR_instruction_mov211(); + void CryptonightR_instruction_mov212(); + void CryptonightR_instruction_mov213(); + void CryptonightR_instruction_mov214(); + void CryptonightR_instruction_mov215(); + void CryptonightR_instruction_mov216(); + void CryptonightR_instruction_mov217(); + void CryptonightR_instruction_mov218(); + void CryptonightR_instruction_mov219(); + void CryptonightR_instruction_mov220(); + void CryptonightR_instruction_mov221(); + void CryptonightR_instruction_mov222(); + void CryptonightR_instruction_mov223(); + void CryptonightR_instruction_mov224(); + void CryptonightR_instruction_mov225(); + void CryptonightR_instruction_mov226(); + void CryptonightR_instruction_mov227(); + void CryptonightR_instruction_mov228(); + void CryptonightR_instruction_mov229(); + void CryptonightR_instruction_mov230(); + void CryptonightR_instruction_mov231(); + void CryptonightR_instruction_mov232(); + void CryptonightR_instruction_mov233(); + void CryptonightR_instruction_mov234(); + void CryptonightR_instruction_mov235(); + void CryptonightR_instruction_mov236(); + void CryptonightR_instruction_mov237(); + void CryptonightR_instruction_mov238(); + void CryptonightR_instruction_mov239(); + void CryptonightR_instruction_mov240(); + void CryptonightR_instruction_mov241(); + void CryptonightR_instruction_mov242(); + void CryptonightR_instruction_mov243(); + void CryptonightR_instruction_mov244(); + void CryptonightR_instruction_mov245(); + void CryptonightR_instruction_mov246(); + void CryptonightR_instruction_mov247(); + void CryptonightR_instruction_mov248(); + void CryptonightR_instruction_mov249(); + void CryptonightR_instruction_mov250(); + void CryptonightR_instruction_mov251(); + void CryptonightR_instruction_mov252(); + void CryptonightR_instruction_mov253(); + void CryptonightR_instruction_mov254(); + void CryptonightR_instruction_mov255(); + void CryptonightR_instruction_mov256(); +} + +const void_func instructions[257] = { + CryptonightR_instruction0, + CryptonightR_instruction1, + CryptonightR_instruction2, + CryptonightR_instruction3, + CryptonightR_instruction4, + CryptonightR_instruction5, + CryptonightR_instruction6, + CryptonightR_instruction7, + CryptonightR_instruction8, + CryptonightR_instruction9, + CryptonightR_instruction10, + CryptonightR_instruction11, + CryptonightR_instruction12, + CryptonightR_instruction13, + CryptonightR_instruction14, + CryptonightR_instruction15, + CryptonightR_instruction16, + CryptonightR_instruction17, + CryptonightR_instruction18, + CryptonightR_instruction19, + CryptonightR_instruction20, + CryptonightR_instruction21, + CryptonightR_instruction22, + CryptonightR_instruction23, + CryptonightR_instruction24, + CryptonightR_instruction25, + CryptonightR_instruction26, + CryptonightR_instruction27, + CryptonightR_instruction28, + CryptonightR_instruction29, + CryptonightR_instruction30, + CryptonightR_instruction31, + CryptonightR_instruction32, + CryptonightR_instruction33, + CryptonightR_instruction34, + CryptonightR_instruction35, + CryptonightR_instruction36, + CryptonightR_instruction37, + CryptonightR_instruction38, + CryptonightR_instruction39, + CryptonightR_instruction40, + CryptonightR_instruction41, + CryptonightR_instruction42, + CryptonightR_instruction43, + CryptonightR_instruction44, + CryptonightR_instruction45, + CryptonightR_instruction46, + CryptonightR_instruction47, + CryptonightR_instruction48, + CryptonightR_instruction49, + CryptonightR_instruction50, + CryptonightR_instruction51, + CryptonightR_instruction52, + CryptonightR_instruction53, + CryptonightR_instruction54, + CryptonightR_instruction55, + CryptonightR_instruction56, + CryptonightR_instruction57, + CryptonightR_instruction58, + CryptonightR_instruction59, + CryptonightR_instruction60, + CryptonightR_instruction61, + CryptonightR_instruction62, + CryptonightR_instruction63, + CryptonightR_instruction64, + CryptonightR_instruction65, + CryptonightR_instruction66, + CryptonightR_instruction67, + CryptonightR_instruction68, + CryptonightR_instruction69, + CryptonightR_instruction70, + CryptonightR_instruction71, + CryptonightR_instruction72, + CryptonightR_instruction73, + CryptonightR_instruction74, + CryptonightR_instruction75, + CryptonightR_instruction76, + CryptonightR_instruction77, + CryptonightR_instruction78, + CryptonightR_instruction79, + CryptonightR_instruction80, + CryptonightR_instruction81, + CryptonightR_instruction82, + CryptonightR_instruction83, + CryptonightR_instruction84, + CryptonightR_instruction85, + CryptonightR_instruction86, + CryptonightR_instruction87, + CryptonightR_instruction88, + CryptonightR_instruction89, + CryptonightR_instruction90, + CryptonightR_instruction91, + CryptonightR_instruction92, + CryptonightR_instruction93, + CryptonightR_instruction94, + CryptonightR_instruction95, + CryptonightR_instruction96, + CryptonightR_instruction97, + CryptonightR_instruction98, + CryptonightR_instruction99, + CryptonightR_instruction100, + CryptonightR_instruction101, + CryptonightR_instruction102, + CryptonightR_instruction103, + CryptonightR_instruction104, + CryptonightR_instruction105, + CryptonightR_instruction106, + CryptonightR_instruction107, + CryptonightR_instruction108, + CryptonightR_instruction109, + CryptonightR_instruction110, + CryptonightR_instruction111, + CryptonightR_instruction112, + CryptonightR_instruction113, + CryptonightR_instruction114, + CryptonightR_instruction115, + CryptonightR_instruction116, + CryptonightR_instruction117, + CryptonightR_instruction118, + CryptonightR_instruction119, + CryptonightR_instruction120, + CryptonightR_instruction121, + CryptonightR_instruction122, + CryptonightR_instruction123, + CryptonightR_instruction124, + CryptonightR_instruction125, + CryptonightR_instruction126, + CryptonightR_instruction127, + CryptonightR_instruction128, + CryptonightR_instruction129, + CryptonightR_instruction130, + CryptonightR_instruction131, + CryptonightR_instruction132, + CryptonightR_instruction133, + CryptonightR_instruction134, + CryptonightR_instruction135, + CryptonightR_instruction136, + CryptonightR_instruction137, + CryptonightR_instruction138, + CryptonightR_instruction139, + CryptonightR_instruction140, + CryptonightR_instruction141, + CryptonightR_instruction142, + CryptonightR_instruction143, + CryptonightR_instruction144, + CryptonightR_instruction145, + CryptonightR_instruction146, + CryptonightR_instruction147, + CryptonightR_instruction148, + CryptonightR_instruction149, + CryptonightR_instruction150, + CryptonightR_instruction151, + CryptonightR_instruction152, + CryptonightR_instruction153, + CryptonightR_instruction154, + CryptonightR_instruction155, + CryptonightR_instruction156, + CryptonightR_instruction157, + CryptonightR_instruction158, + CryptonightR_instruction159, + CryptonightR_instruction160, + CryptonightR_instruction161, + CryptonightR_instruction162, + CryptonightR_instruction163, + CryptonightR_instruction164, + CryptonightR_instruction165, + CryptonightR_instruction166, + CryptonightR_instruction167, + CryptonightR_instruction168, + CryptonightR_instruction169, + CryptonightR_instruction170, + CryptonightR_instruction171, + CryptonightR_instruction172, + CryptonightR_instruction173, + CryptonightR_instruction174, + CryptonightR_instruction175, + CryptonightR_instruction176, + CryptonightR_instruction177, + CryptonightR_instruction178, + CryptonightR_instruction179, + CryptonightR_instruction180, + CryptonightR_instruction181, + CryptonightR_instruction182, + CryptonightR_instruction183, + CryptonightR_instruction184, + CryptonightR_instruction185, + CryptonightR_instruction186, + CryptonightR_instruction187, + CryptonightR_instruction188, + CryptonightR_instruction189, + CryptonightR_instruction190, + CryptonightR_instruction191, + CryptonightR_instruction192, + CryptonightR_instruction193, + CryptonightR_instruction194, + CryptonightR_instruction195, + CryptonightR_instruction196, + CryptonightR_instruction197, + CryptonightR_instruction198, + CryptonightR_instruction199, + CryptonightR_instruction200, + CryptonightR_instruction201, + CryptonightR_instruction202, + CryptonightR_instruction203, + CryptonightR_instruction204, + CryptonightR_instruction205, + CryptonightR_instruction206, + CryptonightR_instruction207, + CryptonightR_instruction208, + CryptonightR_instruction209, + CryptonightR_instruction210, + CryptonightR_instruction211, + CryptonightR_instruction212, + CryptonightR_instruction213, + CryptonightR_instruction214, + CryptonightR_instruction215, + CryptonightR_instruction216, + CryptonightR_instruction217, + CryptonightR_instruction218, + CryptonightR_instruction219, + CryptonightR_instruction220, + CryptonightR_instruction221, + CryptonightR_instruction222, + CryptonightR_instruction223, + CryptonightR_instruction224, + CryptonightR_instruction225, + CryptonightR_instruction226, + CryptonightR_instruction227, + CryptonightR_instruction228, + CryptonightR_instruction229, + CryptonightR_instruction230, + CryptonightR_instruction231, + CryptonightR_instruction232, + CryptonightR_instruction233, + CryptonightR_instruction234, + CryptonightR_instruction235, + CryptonightR_instruction236, + CryptonightR_instruction237, + CryptonightR_instruction238, + CryptonightR_instruction239, + CryptonightR_instruction240, + CryptonightR_instruction241, + CryptonightR_instruction242, + CryptonightR_instruction243, + CryptonightR_instruction244, + CryptonightR_instruction245, + CryptonightR_instruction246, + CryptonightR_instruction247, + CryptonightR_instruction248, + CryptonightR_instruction249, + CryptonightR_instruction250, + CryptonightR_instruction251, + CryptonightR_instruction252, + CryptonightR_instruction253, + CryptonightR_instruction254, + CryptonightR_instruction255, + CryptonightR_instruction256, +}; + +const void_func instructions_mov[257] = { + CryptonightR_instruction_mov0, + CryptonightR_instruction_mov1, + CryptonightR_instruction_mov2, + CryptonightR_instruction_mov3, + CryptonightR_instruction_mov4, + CryptonightR_instruction_mov5, + CryptonightR_instruction_mov6, + CryptonightR_instruction_mov7, + CryptonightR_instruction_mov8, + CryptonightR_instruction_mov9, + CryptonightR_instruction_mov10, + CryptonightR_instruction_mov11, + CryptonightR_instruction_mov12, + CryptonightR_instruction_mov13, + CryptonightR_instruction_mov14, + CryptonightR_instruction_mov15, + CryptonightR_instruction_mov16, + CryptonightR_instruction_mov17, + CryptonightR_instruction_mov18, + CryptonightR_instruction_mov19, + CryptonightR_instruction_mov20, + CryptonightR_instruction_mov21, + CryptonightR_instruction_mov22, + CryptonightR_instruction_mov23, + CryptonightR_instruction_mov24, + CryptonightR_instruction_mov25, + CryptonightR_instruction_mov26, + CryptonightR_instruction_mov27, + CryptonightR_instruction_mov28, + CryptonightR_instruction_mov29, + CryptonightR_instruction_mov30, + CryptonightR_instruction_mov31, + CryptonightR_instruction_mov32, + CryptonightR_instruction_mov33, + CryptonightR_instruction_mov34, + CryptonightR_instruction_mov35, + CryptonightR_instruction_mov36, + CryptonightR_instruction_mov37, + CryptonightR_instruction_mov38, + CryptonightR_instruction_mov39, + CryptonightR_instruction_mov40, + CryptonightR_instruction_mov41, + CryptonightR_instruction_mov42, + CryptonightR_instruction_mov43, + CryptonightR_instruction_mov44, + CryptonightR_instruction_mov45, + CryptonightR_instruction_mov46, + CryptonightR_instruction_mov47, + CryptonightR_instruction_mov48, + CryptonightR_instruction_mov49, + CryptonightR_instruction_mov50, + CryptonightR_instruction_mov51, + CryptonightR_instruction_mov52, + CryptonightR_instruction_mov53, + CryptonightR_instruction_mov54, + CryptonightR_instruction_mov55, + CryptonightR_instruction_mov56, + CryptonightR_instruction_mov57, + CryptonightR_instruction_mov58, + CryptonightR_instruction_mov59, + CryptonightR_instruction_mov60, + CryptonightR_instruction_mov61, + CryptonightR_instruction_mov62, + CryptonightR_instruction_mov63, + CryptonightR_instruction_mov64, + CryptonightR_instruction_mov65, + CryptonightR_instruction_mov66, + CryptonightR_instruction_mov67, + CryptonightR_instruction_mov68, + CryptonightR_instruction_mov69, + CryptonightR_instruction_mov70, + CryptonightR_instruction_mov71, + CryptonightR_instruction_mov72, + CryptonightR_instruction_mov73, + CryptonightR_instruction_mov74, + CryptonightR_instruction_mov75, + CryptonightR_instruction_mov76, + CryptonightR_instruction_mov77, + CryptonightR_instruction_mov78, + CryptonightR_instruction_mov79, + CryptonightR_instruction_mov80, + CryptonightR_instruction_mov81, + CryptonightR_instruction_mov82, + CryptonightR_instruction_mov83, + CryptonightR_instruction_mov84, + CryptonightR_instruction_mov85, + CryptonightR_instruction_mov86, + CryptonightR_instruction_mov87, + CryptonightR_instruction_mov88, + CryptonightR_instruction_mov89, + CryptonightR_instruction_mov90, + CryptonightR_instruction_mov91, + CryptonightR_instruction_mov92, + CryptonightR_instruction_mov93, + CryptonightR_instruction_mov94, + CryptonightR_instruction_mov95, + CryptonightR_instruction_mov96, + CryptonightR_instruction_mov97, + CryptonightR_instruction_mov98, + CryptonightR_instruction_mov99, + CryptonightR_instruction_mov100, + CryptonightR_instruction_mov101, + CryptonightR_instruction_mov102, + CryptonightR_instruction_mov103, + CryptonightR_instruction_mov104, + CryptonightR_instruction_mov105, + CryptonightR_instruction_mov106, + CryptonightR_instruction_mov107, + CryptonightR_instruction_mov108, + CryptonightR_instruction_mov109, + CryptonightR_instruction_mov110, + CryptonightR_instruction_mov111, + CryptonightR_instruction_mov112, + CryptonightR_instruction_mov113, + CryptonightR_instruction_mov114, + CryptonightR_instruction_mov115, + CryptonightR_instruction_mov116, + CryptonightR_instruction_mov117, + CryptonightR_instruction_mov118, + CryptonightR_instruction_mov119, + CryptonightR_instruction_mov120, + CryptonightR_instruction_mov121, + CryptonightR_instruction_mov122, + CryptonightR_instruction_mov123, + CryptonightR_instruction_mov124, + CryptonightR_instruction_mov125, + CryptonightR_instruction_mov126, + CryptonightR_instruction_mov127, + CryptonightR_instruction_mov128, + CryptonightR_instruction_mov129, + CryptonightR_instruction_mov130, + CryptonightR_instruction_mov131, + CryptonightR_instruction_mov132, + CryptonightR_instruction_mov133, + CryptonightR_instruction_mov134, + CryptonightR_instruction_mov135, + CryptonightR_instruction_mov136, + CryptonightR_instruction_mov137, + CryptonightR_instruction_mov138, + CryptonightR_instruction_mov139, + CryptonightR_instruction_mov140, + CryptonightR_instruction_mov141, + CryptonightR_instruction_mov142, + CryptonightR_instruction_mov143, + CryptonightR_instruction_mov144, + CryptonightR_instruction_mov145, + CryptonightR_instruction_mov146, + CryptonightR_instruction_mov147, + CryptonightR_instruction_mov148, + CryptonightR_instruction_mov149, + CryptonightR_instruction_mov150, + CryptonightR_instruction_mov151, + CryptonightR_instruction_mov152, + CryptonightR_instruction_mov153, + CryptonightR_instruction_mov154, + CryptonightR_instruction_mov155, + CryptonightR_instruction_mov156, + CryptonightR_instruction_mov157, + CryptonightR_instruction_mov158, + CryptonightR_instruction_mov159, + CryptonightR_instruction_mov160, + CryptonightR_instruction_mov161, + CryptonightR_instruction_mov162, + CryptonightR_instruction_mov163, + CryptonightR_instruction_mov164, + CryptonightR_instruction_mov165, + CryptonightR_instruction_mov166, + CryptonightR_instruction_mov167, + CryptonightR_instruction_mov168, + CryptonightR_instruction_mov169, + CryptonightR_instruction_mov170, + CryptonightR_instruction_mov171, + CryptonightR_instruction_mov172, + CryptonightR_instruction_mov173, + CryptonightR_instruction_mov174, + CryptonightR_instruction_mov175, + CryptonightR_instruction_mov176, + CryptonightR_instruction_mov177, + CryptonightR_instruction_mov178, + CryptonightR_instruction_mov179, + CryptonightR_instruction_mov180, + CryptonightR_instruction_mov181, + CryptonightR_instruction_mov182, + CryptonightR_instruction_mov183, + CryptonightR_instruction_mov184, + CryptonightR_instruction_mov185, + CryptonightR_instruction_mov186, + CryptonightR_instruction_mov187, + CryptonightR_instruction_mov188, + CryptonightR_instruction_mov189, + CryptonightR_instruction_mov190, + CryptonightR_instruction_mov191, + CryptonightR_instruction_mov192, + CryptonightR_instruction_mov193, + CryptonightR_instruction_mov194, + CryptonightR_instruction_mov195, + CryptonightR_instruction_mov196, + CryptonightR_instruction_mov197, + CryptonightR_instruction_mov198, + CryptonightR_instruction_mov199, + CryptonightR_instruction_mov200, + CryptonightR_instruction_mov201, + CryptonightR_instruction_mov202, + CryptonightR_instruction_mov203, + CryptonightR_instruction_mov204, + CryptonightR_instruction_mov205, + CryptonightR_instruction_mov206, + CryptonightR_instruction_mov207, + CryptonightR_instruction_mov208, + CryptonightR_instruction_mov209, + CryptonightR_instruction_mov210, + CryptonightR_instruction_mov211, + CryptonightR_instruction_mov212, + CryptonightR_instruction_mov213, + CryptonightR_instruction_mov214, + CryptonightR_instruction_mov215, + CryptonightR_instruction_mov216, + CryptonightR_instruction_mov217, + CryptonightR_instruction_mov218, + CryptonightR_instruction_mov219, + CryptonightR_instruction_mov220, + CryptonightR_instruction_mov221, + CryptonightR_instruction_mov222, + CryptonightR_instruction_mov223, + CryptonightR_instruction_mov224, + CryptonightR_instruction_mov225, + CryptonightR_instruction_mov226, + CryptonightR_instruction_mov227, + CryptonightR_instruction_mov228, + CryptonightR_instruction_mov229, + CryptonightR_instruction_mov230, + CryptonightR_instruction_mov231, + CryptonightR_instruction_mov232, + CryptonightR_instruction_mov233, + CryptonightR_instruction_mov234, + CryptonightR_instruction_mov235, + CryptonightR_instruction_mov236, + CryptonightR_instruction_mov237, + CryptonightR_instruction_mov238, + CryptonightR_instruction_mov239, + CryptonightR_instruction_mov240, + CryptonightR_instruction_mov241, + CryptonightR_instruction_mov242, + CryptonightR_instruction_mov243, + CryptonightR_instruction_mov244, + CryptonightR_instruction_mov245, + CryptonightR_instruction_mov246, + CryptonightR_instruction_mov247, + CryptonightR_instruction_mov248, + CryptonightR_instruction_mov249, + CryptonightR_instruction_mov250, + CryptonightR_instruction_mov251, + CryptonightR_instruction_mov252, + CryptonightR_instruction_mov253, + CryptonightR_instruction_mov254, + CryptonightR_instruction_mov255, + CryptonightR_instruction_mov256, +}; diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.inc b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.inc new file mode 100644 index 000000000..1dae434a2 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.inc @@ -0,0 +1,529 @@ +PUBLIC FN_PREFIX(CryptonightR_template_part1) +PUBLIC FN_PREFIX(CryptonightR_template_mainloop) +PUBLIC FN_PREFIX(CryptonightR_template_part2) +PUBLIC FN_PREFIX(CryptonightR_template_part3) +PUBLIC FN_PREFIX(CryptonightR_template_end) +PUBLIC FN_PREFIX(CryptonightR_template_double_part1) +PUBLIC FN_PREFIX(CryptonightR_template_double_mainloop) +PUBLIC FN_PREFIX(CryptonightR_template_double_part2) +PUBLIC FN_PREFIX(CryptonightR_template_double_part3) +PUBLIC FN_PREFIX(CryptonightR_template_double_part4) +PUBLIC FN_PREFIX(CryptonightR_template_double_end) + +ALIGN(64) +FN_PREFIX(CryptonightR_template_part1): + mov QWORD PTR [rsp+16], rbx + mov QWORD PTR [rsp+24], rbp + mov QWORD PTR [rsp+32], rsi + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + push rdi + sub rsp, 64 + mov r12, rcx + mov r8, QWORD PTR [r12+32] + mov rdx, r12 + xor r8, QWORD PTR [r12] + mov r15, QWORD PTR [r12+40] + mov r9, r8 + xor r15, QWORD PTR [r12+8] + mov r11, QWORD PTR [r12+224] + mov r12, QWORD PTR [r12+56] + xor r12, QWORD PTR [rdx+24] + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + movaps XMMWORD PTR [rsp+48], xmm6 + movd xmm0, r12 + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+16], xmm8 + movaps XMMWORD PTR [rsp], xmm9 + mov r12, QWORD PTR [rdx+88] + xor r12, QWORD PTR [rdx+72] + movd xmm6, rax + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm6, xmm0 + and r9d, 2097136 + movd xmm0, r12 + movd xmm7, rax + punpcklqdq xmm7, xmm0 + mov r10d, r9d + movd xmm9, rsp + mov rsp, r8 + mov r8d, 524288 + + mov ebx, [rdx+96] + mov esi, [rdx+100] + mov edi, [rdx+104] + mov ebp, [rdx+108] + + ALIGN(64) +FN_PREFIX(CryptonightR_template_mainloop): + movdqa xmm5, XMMWORD PTR [r9+r11] + movd xmm0, r15 + movd xmm4, rsp + punpcklqdq xmm4, xmm0 + lea rdx, QWORD PTR [r9+r11] + + aesenc xmm5, xmm4 + + mov r12d, r9d + mov eax, r9d + xor r9d, 48 + xor r12d, 16 + xor eax, 32 + movdqu xmm0, XMMWORD PTR [r9+r11] + movaps xmm3, xmm0 + movdqu xmm2, XMMWORD PTR [r12+r11] + movdqu xmm1, XMMWORD PTR [rax+r11] + pxor xmm0, xmm2 + pxor xmm5, xmm1 + pxor xmm5, xmm0 + paddq xmm3, xmm7 + paddq xmm2, xmm6 + paddq xmm1, xmm4 + movdqu XMMWORD PTR [r12+r11], xmm3 + movdqu XMMWORD PTR [rax+r11], xmm2 + movdqu XMMWORD PTR [r9+r11], xmm1 + + movd r12, xmm5 + movd r10d, xmm5 + and r10d, 2097136 + + movdqa xmm0, xmm5 + pxor xmm0, xmm6 + movdqu XMMWORD PTR [rdx], xmm0 + + lea r13d, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or r13, rdx + + xor r13, QWORD PTR [r10+r11] + mov r14, QWORD PTR [r10+r11+8] + + movd eax, xmm6 + movd edx, xmm7 + pextrd r9d, xmm7, 2 + +FN_PREFIX(CryptonightR_template_part2): + mov eax, edi + mov edx, ebp + shl rdx, 32 + or rax, rdx + xor rsp, rax + + mov eax, ebx + mov edx, esi + shl rdx, 32 + or rax, rdx + xor r15, rax + + mov rax, r13 + mul r12 + + mov r9d, r10d + mov r12d, r10d + xor r9d, 16 + xor r12d, 32 + xor r10d, 48 + movdqa xmm1, XMMWORD PTR [r12+r11] + movaps xmm3, xmm1 + movdqa xmm2, XMMWORD PTR [r9+r11] + movdqa xmm0, XMMWORD PTR [r10+r11] + pxor xmm1, xmm2 + pxor xmm5, xmm0 + pxor xmm5, xmm1 + paddq xmm3, xmm4 + paddq xmm2, xmm6 + paddq xmm0, xmm7 + movdqu XMMWORD PTR [r9+r11], xmm0 + movdqu XMMWORD PTR [r12+r11], xmm2 + movdqu XMMWORD PTR [r10+r11], xmm3 + + movdqa xmm7, xmm6 + add r15, rax + add rsp, rdx + xor r10, 48 + mov QWORD PTR [r10+r11], rsp + xor rsp, r13 + mov r9d, esp + mov QWORD PTR [r10+r11+8], r15 + and r9d, 2097136 + xor r15, r14 + movdqa xmm6, xmm5 + dec r8d + jnz FN_PREFIX(CryptonightR_template_mainloop) + +FN_PREFIX(CryptonightR_template_part3): + movd rsp, xmm9 + + mov rbx, QWORD PTR [rsp+136] + mov rbp, QWORD PTR [rsp+144] + mov rsi, QWORD PTR [rsp+152] + movaps xmm6, XMMWORD PTR [rsp+48] + movaps xmm7, XMMWORD PTR [rsp+32] + movaps xmm8, XMMWORD PTR [rsp+16] + movaps xmm9, XMMWORD PTR [rsp] + add rsp, 64 + pop rdi + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + ret 0 +FN_PREFIX(CryptonightR_template_end): + +ALIGN(64) +FN_PREFIX(CryptonightR_template_double_part1): + mov QWORD PTR [rsp+24], rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 320 + mov r14, QWORD PTR [rcx+32] + mov r8, rcx + xor r14, QWORD PTR [rcx] + mov r12, QWORD PTR [rcx+40] + mov ebx, r14d + mov rsi, QWORD PTR [rcx+224] + and ebx, 2097136 + xor r12, QWORD PTR [rcx+8] + mov rcx, QWORD PTR [rcx+56] + xor rcx, QWORD PTR [r8+24] + mov rax, QWORD PTR [r8+48] + xor rax, QWORD PTR [r8+16] + mov r15, QWORD PTR [rdx+32] + xor r15, QWORD PTR [rdx] + movd xmm0, rcx + mov rcx, QWORD PTR [r8+88] + xor rcx, QWORD PTR [r8+72] + mov r13, QWORD PTR [rdx+40] + mov rdi, QWORD PTR [rdx+224] + xor r13, QWORD PTR [rdx+8] + movaps XMMWORD PTR [rsp+160], xmm6 + movaps XMMWORD PTR [rsp+176], xmm7 + movaps XMMWORD PTR [rsp+192], xmm8 + movaps XMMWORD PTR [rsp+208], xmm9 + movaps XMMWORD PTR [rsp+224], xmm10 + movaps XMMWORD PTR [rsp+240], xmm11 + movaps XMMWORD PTR [rsp+256], xmm12 + movaps XMMWORD PTR [rsp+272], xmm13 + movaps XMMWORD PTR [rsp+288], xmm14 + movaps XMMWORD PTR [rsp+304], xmm15 + movd xmm7, rax + mov rax, QWORD PTR [r8+80] + xor rax, QWORD PTR [r8+64] + + movaps xmm1, XMMWORD PTR [rdx+96] + movaps xmm2, XMMWORD PTR [r8+96] + movaps XMMWORD PTR [rsp], xmm1 + movaps XMMWORD PTR [rsp+16], xmm2 + + mov r8d, r15d + punpcklqdq xmm7, xmm0 + movd xmm0, rcx + mov rcx, QWORD PTR [rdx+56] + xor rcx, QWORD PTR [rdx+24] + movd xmm9, rax + mov QWORD PTR [rsp+128], rsi + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + punpcklqdq xmm9, xmm0 + movd xmm0, rcx + mov rcx, QWORD PTR [rdx+88] + xor rcx, QWORD PTR [rdx+72] + movd xmm8, rax + mov QWORD PTR [rsp+136], rdi + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm8, xmm0 + and r8d, 2097136 + movd xmm0, rcx + mov r11d, 524288 + movd xmm10, rax + punpcklqdq xmm10, xmm0 + + movd xmm14, QWORD PTR [rsp+128] + movd xmm15, QWORD PTR [rsp+136] + + ALIGN(64) +FN_PREFIX(CryptonightR_template_double_mainloop): + movdqu xmm6, XMMWORD PTR [rbx+rsi] + movd xmm0, r12 + mov ecx, ebx + movd xmm3, r14 + punpcklqdq xmm3, xmm0 + xor ebx, 16 + aesenc xmm6, xmm3 + movd xmm4, r15 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + pxor xmm6, xmm0 + xor ebx, 48 + paddq xmm0, xmm7 + movdqu xmm1, XMMWORD PTR [rbx+rsi] + pxor xmm6, xmm1 + movdqu XMMWORD PTR [rbx+rsi], xmm0 + paddq xmm1, xmm3 + xor ebx, 16 + mov eax, ebx + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + pxor xmm6, xmm0 + movd rdx, xmm6 + movdqu XMMWORD PTR [rbx+rsi], xmm1 + paddq xmm0, xmm9 + movdqu XMMWORD PTR [rax+rsi], xmm0 + movdqa xmm0, xmm6 + pxor xmm0, xmm7 + movdqu XMMWORD PTR [rcx+rsi], xmm0 + mov esi, edx + movdqu xmm5, XMMWORD PTR [r8+rdi] + and esi, 2097136 + mov ecx, r8d + movd xmm0, r13 + punpcklqdq xmm4, xmm0 + xor r8d, 16 + aesenc xmm5, xmm4 + movdqu xmm0, XMMWORD PTR [r8+rdi] + pxor xmm5, xmm0 + xor r8d, 48 + paddq xmm0, xmm8 + movdqu xmm1, XMMWORD PTR [r8+rdi] + pxor xmm5, xmm1 + movdqu XMMWORD PTR [r8+rdi], xmm0 + paddq xmm1, xmm4 + xor r8d, 16 + mov eax, r8d + xor rax, 32 + movdqu xmm0, XMMWORD PTR [r8+rdi] + pxor xmm5, xmm0 + movdqu XMMWORD PTR [r8+rdi], xmm1 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rdi], xmm0 + movdqa xmm0, xmm5 + pxor xmm0, xmm8 + movdqu XMMWORD PTR [rcx+rdi], xmm0 + movd rdi, xmm5 + movd rcx, xmm14 + mov ebp, edi + mov r8, QWORD PTR [rcx+rsi] + mov r10, QWORD PTR [rcx+rsi+8] + lea r9, QWORD PTR [rcx+rsi] + xor esi, 16 + + movd xmm0, rsp + movd xmm1, rsi + movd xmm2, rdi + movd xmm11, rbp + movd xmm12, r15 + movd xmm13, rdx + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp+16] + mov esi, DWORD PTR [rsp+20] + mov edi, DWORD PTR [rsp+24] + mov ebp, DWORD PTR [rsp+28] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + xor r8, rax + + movd esp, xmm3 + pextrd r15d, xmm3, 2 + movd eax, xmm7 + movd edx, xmm9 + pextrd r9d, xmm9, 2 + +FN_PREFIX(CryptonightR_template_double_part2): + + mov eax, edi + mov edx, ebp + shl rdx, 32 + or rax, rdx + xor r14, rax + + mov eax, ebx + mov edx, esi + shl rdx, 32 + or rax, rdx + xor r12, rax + + movd rsp, xmm0 + mov DWORD PTR [rsp+16], ebx + mov DWORD PTR [rsp+20], esi + mov DWORD PTR [rsp+24], edi + mov DWORD PTR [rsp+28], ebp + + movd rsi, xmm1 + movd rdi, xmm2 + movd rbp, xmm11 + movd r15, xmm12 + movd rdx, xmm13 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rbx, r8 + mov rax, r8 + mul rdx + and ebp, 2097136 + mov r8, rax + movdqu xmm1, XMMWORD PTR [rcx+rsi] + pxor xmm6, xmm1 + xor esi, 48 + paddq xmm1, xmm7 + movdqu xmm2, XMMWORD PTR [rsi+rcx] + pxor xmm6, xmm2 + paddq xmm2, xmm3 + movdqu XMMWORD PTR [rsi+rcx], xmm1 + xor esi, 16 + mov eax, esi + mov rsi, rcx + movdqu xmm0, XMMWORD PTR [rax+rcx] + pxor xmm6, xmm0 + movdqu XMMWORD PTR [rax+rcx], xmm2 + paddq xmm0, xmm9 + add r12, r8 + xor rax, 32 + add r14, rdx + movdqa xmm9, xmm7 + movdqa xmm7, xmm6 + movdqu XMMWORD PTR [rax+rcx], xmm0 + mov QWORD PTR [r9+8], r12 + xor r12, r10 + mov QWORD PTR [r9], r14 + movd rcx, xmm15 + xor r14, rbx + mov r10d, ebp + mov ebx, r14d + xor ebp, 16 + and ebx, 2097136 + mov r8, QWORD PTR [r10+rcx] + mov r9, QWORD PTR [r10+rcx+8] + + movd xmm0, rsp + movd xmm1, rbx + movd xmm2, rsi + movd xmm11, rdi + movd xmm12, rbp + movd xmm13, r15 + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp] + mov esi, DWORD PTR [rsp+4] + mov edi, DWORD PTR [rsp+8] + mov ebp, DWORD PTR [rsp+12] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + + xor r8, rax + movd xmm3, r8 + + movd esp, xmm4 + pextrd r15d, xmm4, 2 + movd eax, xmm8 + movd edx, xmm10 + pextrd r9d, xmm10, 2 + +FN_PREFIX(CryptonightR_template_double_part3): + + movd r15, xmm13 + + mov eax, edi + mov edx, ebp + shl rdx, 32 + or rax, rdx + xor r15, rax + + mov eax, ebx + mov edx, esi + shl rdx, 32 + or rax, rdx + xor r13, rax + + movd rsp, xmm0 + mov DWORD PTR [rsp], ebx + mov DWORD PTR [rsp+4], esi + mov DWORD PTR [rsp+8], edi + mov DWORD PTR [rsp+12], ebp + + movd rbx, xmm1 + movd rsi, xmm2 + movd rdi, xmm11 + movd rbp, xmm12 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rax, r8 + mul rdi + mov rdi, rcx + mov r8, rax + movdqu xmm1, XMMWORD PTR [rbp+rcx] + pxor xmm5, xmm1 + xor ebp, 48 + paddq xmm1, xmm8 + add r13, r8 + movdqu xmm2, XMMWORD PTR [rbp+rcx] + pxor xmm5, xmm2 + add r15, rdx + movdqu XMMWORD PTR [rbp+rcx], xmm1 + paddq xmm2, xmm4 + xor ebp, 16 + mov eax, ebp + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbp+rcx] + pxor xmm5, xmm0 + movdqu XMMWORD PTR [rbp+rcx], xmm2 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rcx], xmm0 + movd rax, xmm3 + movdqa xmm10, xmm8 + mov QWORD PTR [r10+rcx], r15 + movdqa xmm8, xmm5 + xor r15, rax + mov QWORD PTR [r10+rcx+8], r13 + mov r8d, r15d + xor r13, r9 + and r8d, 2097136 + dec r11d + jnz FN_PREFIX(CryptonightR_template_double_mainloop) + +FN_PREFIX(CryptonightR_template_double_part4): + + mov rbx, QWORD PTR [rsp+400] + movaps xmm6, XMMWORD PTR [rsp+160] + movaps xmm7, XMMWORD PTR [rsp+176] + movaps xmm8, XMMWORD PTR [rsp+192] + movaps xmm9, XMMWORD PTR [rsp+208] + movaps xmm10, XMMWORD PTR [rsp+224] + movaps xmm11, XMMWORD PTR [rsp+240] + movaps xmm12, XMMWORD PTR [rsp+256] + movaps xmm13, XMMWORD PTR [rsp+272] + movaps xmm14, XMMWORD PTR [rsp+288] + movaps xmm15, XMMWORD PTR [rsp+304] + add rsp, 320 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + ret 0 +FN_PREFIX(CryptonightR_template_double_end): diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template_win.inc b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template_win.inc new file mode 100644 index 000000000..2f2d71a25 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template_win.inc @@ -0,0 +1,529 @@ +PUBLIC CryptonightR_template_part1 +PUBLIC CryptonightR_template_mainloop +PUBLIC CryptonightR_template_part2 +PUBLIC CryptonightR_template_part3 +PUBLIC CryptonightR_template_end +PUBLIC CryptonightR_template_double_part1 +PUBLIC CryptonightR_template_double_mainloop +PUBLIC CryptonightR_template_double_part2 +PUBLIC CryptonightR_template_double_part3 +PUBLIC CryptonightR_template_double_part4 +PUBLIC CryptonightR_template_double_end + +ALIGN(64) +CryptonightR_template_part1: + mov QWORD PTR [rsp+16], rbx + mov QWORD PTR [rsp+24], rbp + mov QWORD PTR [rsp+32], rsi + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + push rdi + sub rsp, 64 + mov r12, rcx + mov r8, QWORD PTR [r12+32] + mov rdx, r12 + xor r8, QWORD PTR [r12] + mov r15, QWORD PTR [r12+40] + mov r9, r8 + xor r15, QWORD PTR [r12+8] + mov r11, QWORD PTR [r12+224] + mov r12, QWORD PTR [r12+56] + xor r12, QWORD PTR [rdx+24] + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + movaps XMMWORD PTR [rsp+48], xmm6 + movd xmm0, r12 + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+16], xmm8 + movaps XMMWORD PTR [rsp], xmm9 + mov r12, QWORD PTR [rdx+88] + xor r12, QWORD PTR [rdx+72] + movd xmm6, rax + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm6, xmm0 + and r9d, 2097136 + movd xmm0, r12 + movd xmm7, rax + punpcklqdq xmm7, xmm0 + mov r10d, r9d + movd xmm9, rsp + mov rsp, r8 + mov r8d, 524288 + + mov ebx, [rdx+96] + mov esi, [rdx+100] + mov edi, [rdx+104] + mov ebp, [rdx+108] + + ALIGN(64) +CryptonightR_template_mainloop: + movdqa xmm5, XMMWORD PTR [r9+r11] + movd xmm0, r15 + movd xmm4, rsp + punpcklqdq xmm4, xmm0 + lea rdx, QWORD PTR [r9+r11] + + aesenc xmm5, xmm4 + + mov r12d, r9d + mov eax, r9d + xor r9d, 48 + xor r12d, 16 + xor eax, 32 + movdqu xmm0, XMMWORD PTR [r9+r11] + movaps xmm3, xmm0 + movdqu xmm2, XMMWORD PTR [r12+r11] + movdqu xmm1, XMMWORD PTR [rax+r11] + pxor xmm0, xmm2 + pxor xmm5, xmm1 + pxor xmm5, xmm0 + paddq xmm3, xmm7 + paddq xmm2, xmm6 + paddq xmm1, xmm4 + movdqu XMMWORD PTR [r12+r11], xmm3 + movdqu XMMWORD PTR [rax+r11], xmm2 + movdqu XMMWORD PTR [r9+r11], xmm1 + + movd r12, xmm5 + movd r10d, xmm5 + and r10d, 2097136 + + movdqa xmm0, xmm5 + pxor xmm0, xmm6 + movdqu XMMWORD PTR [rdx], xmm0 + + lea r13d, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or r13, rdx + + xor r13, QWORD PTR [r10+r11] + mov r14, QWORD PTR [r10+r11+8] + + movd eax, xmm6 + movd edx, xmm7 + pextrd r9d, xmm7, 2 + +CryptonightR_template_part2: + mov eax, edi + mov edx, ebp + shl rdx, 32 + or rax, rdx + xor rsp, rax + + mov eax, ebx + mov edx, esi + shl rdx, 32 + or rax, rdx + xor r15, rax + + mov rax, r13 + mul r12 + + mov r9d, r10d + mov r12d, r10d + xor r9d, 16 + xor r12d, 32 + xor r10d, 48 + movdqa xmm1, XMMWORD PTR [r12+r11] + movaps xmm3, xmm1 + movdqa xmm2, XMMWORD PTR [r9+r11] + movdqa xmm0, XMMWORD PTR [r10+r11] + pxor xmm1, xmm2 + pxor xmm5, xmm0 + pxor xmm5, xmm1 + paddq xmm3, xmm4 + paddq xmm2, xmm6 + paddq xmm0, xmm7 + movdqu XMMWORD PTR [r9+r11], xmm0 + movdqu XMMWORD PTR [r12+r11], xmm2 + movdqu XMMWORD PTR [r10+r11], xmm3 + + movdqa xmm7, xmm6 + add r15, rax + add rsp, rdx + xor r10, 48 + mov QWORD PTR [r10+r11], rsp + xor rsp, r13 + mov r9d, esp + mov QWORD PTR [r10+r11+8], r15 + and r9d, 2097136 + xor r15, r14 + movdqa xmm6, xmm5 + dec r8d + jnz CryptonightR_template_mainloop + +CryptonightR_template_part3: + movd rsp, xmm9 + + mov rbx, QWORD PTR [rsp+136] + mov rbp, QWORD PTR [rsp+144] + mov rsi, QWORD PTR [rsp+152] + movaps xmm6, XMMWORD PTR [rsp+48] + movaps xmm7, XMMWORD PTR [rsp+32] + movaps xmm8, XMMWORD PTR [rsp+16] + movaps xmm9, XMMWORD PTR [rsp] + add rsp, 64 + pop rdi + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + ret 0 +CryptonightR_template_end: + +ALIGN(64) +CryptonightR_template_double_part1: + mov QWORD PTR [rsp+24], rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 320 + mov r14, QWORD PTR [rcx+32] + mov r8, rcx + xor r14, QWORD PTR [rcx] + mov r12, QWORD PTR [rcx+40] + mov ebx, r14d + mov rsi, QWORD PTR [rcx+224] + and ebx, 2097136 + xor r12, QWORD PTR [rcx+8] + mov rcx, QWORD PTR [rcx+56] + xor rcx, QWORD PTR [r8+24] + mov rax, QWORD PTR [r8+48] + xor rax, QWORD PTR [r8+16] + mov r15, QWORD PTR [rdx+32] + xor r15, QWORD PTR [rdx] + movd xmm0, rcx + mov rcx, QWORD PTR [r8+88] + xor rcx, QWORD PTR [r8+72] + mov r13, QWORD PTR [rdx+40] + mov rdi, QWORD PTR [rdx+224] + xor r13, QWORD PTR [rdx+8] + movaps XMMWORD PTR [rsp+160], xmm6 + movaps XMMWORD PTR [rsp+176], xmm7 + movaps XMMWORD PTR [rsp+192], xmm8 + movaps XMMWORD PTR [rsp+208], xmm9 + movaps XMMWORD PTR [rsp+224], xmm10 + movaps XMMWORD PTR [rsp+240], xmm11 + movaps XMMWORD PTR [rsp+256], xmm12 + movaps XMMWORD PTR [rsp+272], xmm13 + movaps XMMWORD PTR [rsp+288], xmm14 + movaps XMMWORD PTR [rsp+304], xmm15 + movd xmm7, rax + mov rax, QWORD PTR [r8+80] + xor rax, QWORD PTR [r8+64] + + movaps xmm1, XMMWORD PTR [rdx+96] + movaps xmm2, XMMWORD PTR [r8+96] + movaps XMMWORD PTR [rsp], xmm1 + movaps XMMWORD PTR [rsp+16], xmm2 + + mov r8d, r15d + punpcklqdq xmm7, xmm0 + movd xmm0, rcx + mov rcx, QWORD PTR [rdx+56] + xor rcx, QWORD PTR [rdx+24] + movd xmm9, rax + mov QWORD PTR [rsp+128], rsi + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + punpcklqdq xmm9, xmm0 + movd xmm0, rcx + mov rcx, QWORD PTR [rdx+88] + xor rcx, QWORD PTR [rdx+72] + movd xmm8, rax + mov QWORD PTR [rsp+136], rdi + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm8, xmm0 + and r8d, 2097136 + movd xmm0, rcx + mov r11d, 524288 + movd xmm10, rax + punpcklqdq xmm10, xmm0 + + movd xmm14, QWORD PTR [rsp+128] + movd xmm15, QWORD PTR [rsp+136] + + ALIGN(64) +CryptonightR_template_double_mainloop: + movdqu xmm6, XMMWORD PTR [rbx+rsi] + movd xmm0, r12 + mov ecx, ebx + movd xmm3, r14 + punpcklqdq xmm3, xmm0 + xor ebx, 16 + aesenc xmm6, xmm3 + movd xmm4, r15 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + pxor xmm6, xmm0 + xor ebx, 48 + paddq xmm0, xmm7 + movdqu xmm1, XMMWORD PTR [rbx+rsi] + pxor xmm6, xmm1 + movdqu XMMWORD PTR [rbx+rsi], xmm0 + paddq xmm1, xmm3 + xor ebx, 16 + mov eax, ebx + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + pxor xmm6, xmm0 + movd rdx, xmm6 + movdqu XMMWORD PTR [rbx+rsi], xmm1 + paddq xmm0, xmm9 + movdqu XMMWORD PTR [rax+rsi], xmm0 + movdqa xmm0, xmm6 + pxor xmm0, xmm7 + movdqu XMMWORD PTR [rcx+rsi], xmm0 + mov esi, edx + movdqu xmm5, XMMWORD PTR [r8+rdi] + and esi, 2097136 + mov ecx, r8d + movd xmm0, r13 + punpcklqdq xmm4, xmm0 + xor r8d, 16 + aesenc xmm5, xmm4 + movdqu xmm0, XMMWORD PTR [r8+rdi] + pxor xmm5, xmm0 + xor r8d, 48 + paddq xmm0, xmm8 + movdqu xmm1, XMMWORD PTR [r8+rdi] + pxor xmm5, xmm1 + movdqu XMMWORD PTR [r8+rdi], xmm0 + paddq xmm1, xmm4 + xor r8d, 16 + mov eax, r8d + xor rax, 32 + movdqu xmm0, XMMWORD PTR [r8+rdi] + pxor xmm5, xmm0 + movdqu XMMWORD PTR [r8+rdi], xmm1 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rdi], xmm0 + movdqa xmm0, xmm5 + pxor xmm0, xmm8 + movdqu XMMWORD PTR [rcx+rdi], xmm0 + movd rdi, xmm5 + movd rcx, xmm14 + mov ebp, edi + mov r8, QWORD PTR [rcx+rsi] + mov r10, QWORD PTR [rcx+rsi+8] + lea r9, QWORD PTR [rcx+rsi] + xor esi, 16 + + movd xmm0, rsp + movd xmm1, rsi + movd xmm2, rdi + movd xmm11, rbp + movd xmm12, r15 + movd xmm13, rdx + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp+16] + mov esi, DWORD PTR [rsp+20] + mov edi, DWORD PTR [rsp+24] + mov ebp, DWORD PTR [rsp+28] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + xor r8, rax + + movd esp, xmm3 + pextrd r15d, xmm3, 2 + movd eax, xmm7 + movd edx, xmm9 + pextrd r9d, xmm9, 2 + +CryptonightR_template_double_part2: + + mov eax, edi + mov edx, ebp + shl rdx, 32 + or rax, rdx + xor r14, rax + + mov eax, ebx + mov edx, esi + shl rdx, 32 + or rax, rdx + xor r12, rax + + movd rsp, xmm0 + mov DWORD PTR [rsp+16], ebx + mov DWORD PTR [rsp+20], esi + mov DWORD PTR [rsp+24], edi + mov DWORD PTR [rsp+28], ebp + + movd rsi, xmm1 + movd rdi, xmm2 + movd rbp, xmm11 + movd r15, xmm12 + movd rdx, xmm13 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rbx, r8 + mov rax, r8 + mul rdx + and ebp, 2097136 + mov r8, rax + movdqu xmm1, XMMWORD PTR [rcx+rsi] + pxor xmm6, xmm1 + xor esi, 48 + paddq xmm1, xmm7 + movdqu xmm2, XMMWORD PTR [rsi+rcx] + pxor xmm6, xmm2 + paddq xmm2, xmm3 + movdqu XMMWORD PTR [rsi+rcx], xmm1 + xor esi, 16 + mov eax, esi + mov rsi, rcx + movdqu xmm0, XMMWORD PTR [rax+rcx] + pxor xmm6, xmm0 + movdqu XMMWORD PTR [rax+rcx], xmm2 + paddq xmm0, xmm9 + add r12, r8 + xor rax, 32 + add r14, rdx + movdqa xmm9, xmm7 + movdqa xmm7, xmm6 + movdqu XMMWORD PTR [rax+rcx], xmm0 + mov QWORD PTR [r9+8], r12 + xor r12, r10 + mov QWORD PTR [r9], r14 + movd rcx, xmm15 + xor r14, rbx + mov r10d, ebp + mov ebx, r14d + xor ebp, 16 + and ebx, 2097136 + mov r8, QWORD PTR [r10+rcx] + mov r9, QWORD PTR [r10+rcx+8] + + movd xmm0, rsp + movd xmm1, rbx + movd xmm2, rsi + movd xmm11, rdi + movd xmm12, rbp + movd xmm13, r15 + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp] + mov esi, DWORD PTR [rsp+4] + mov edi, DWORD PTR [rsp+8] + mov ebp, DWORD PTR [rsp+12] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + + xor r8, rax + movd xmm3, r8 + + movd esp, xmm4 + pextrd r15d, xmm4, 2 + movd eax, xmm8 + movd edx, xmm10 + pextrd r9d, xmm10, 2 + +CryptonightR_template_double_part3: + + movd r15, xmm13 + + mov eax, edi + mov edx, ebp + shl rdx, 32 + or rax, rdx + xor r15, rax + + mov eax, ebx + mov edx, esi + shl rdx, 32 + or rax, rdx + xor r13, rax + + movd rsp, xmm0 + mov DWORD PTR [rsp], ebx + mov DWORD PTR [rsp+4], esi + mov DWORD PTR [rsp+8], edi + mov DWORD PTR [rsp+12], ebp + + movd rbx, xmm1 + movd rsi, xmm2 + movd rdi, xmm11 + movd rbp, xmm12 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rax, r8 + mul rdi + mov rdi, rcx + mov r8, rax + movdqu xmm1, XMMWORD PTR [rbp+rcx] + pxor xmm5, xmm1 + xor ebp, 48 + paddq xmm1, xmm8 + add r13, r8 + movdqu xmm2, XMMWORD PTR [rbp+rcx] + pxor xmm5, xmm2 + add r15, rdx + movdqu XMMWORD PTR [rbp+rcx], xmm1 + paddq xmm2, xmm4 + xor ebp, 16 + mov eax, ebp + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbp+rcx] + pxor xmm5, xmm0 + movdqu XMMWORD PTR [rbp+rcx], xmm2 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rcx], xmm0 + movd rax, xmm3 + movdqa xmm10, xmm8 + mov QWORD PTR [r10+rcx], r15 + movdqa xmm8, xmm5 + xor r15, rax + mov QWORD PTR [r10+rcx+8], r13 + mov r8d, r15d + xor r13, r9 + and r8d, 2097136 + dec r11d + jnz CryptonightR_template_double_mainloop + +CryptonightR_template_double_part4: + + mov rbx, QWORD PTR [rsp+400] + movaps xmm6, XMMWORD PTR [rsp+160] + movaps xmm7, XMMWORD PTR [rsp+176] + movaps xmm8, XMMWORD PTR [rsp+192] + movaps xmm9, XMMWORD PTR [rsp+208] + movaps xmm10, XMMWORD PTR [rsp+224] + movaps xmm11, XMMWORD PTR [rsp+240] + movaps xmm12, XMMWORD PTR [rsp+256] + movaps xmm13, XMMWORD PTR [rsp+272] + movaps xmm14, XMMWORD PTR [rsp+288] + movaps xmm15, XMMWORD PTR [rsp+304] + add rsp, 320 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + ret 0 +CryptonightR_template_double_end: diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightWOW_template.inc b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightWOW_template.inc new file mode 100644 index 000000000..47fbc94f8 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightWOW_template.inc @@ -0,0 +1,486 @@ +PUBLIC FN_PREFIX(CryptonightWOW_template_part1) +PUBLIC FN_PREFIX(CryptonightWOW_template_mainloop) +PUBLIC FN_PREFIX(CryptonightWOW_template_part2) +PUBLIC FN_PREFIX(CryptonightWOW_template_part3) +PUBLIC FN_PREFIX(CryptonightWOW_template_end) +PUBLIC FN_PREFIX(CryptonightWOW_template_double_part1) +PUBLIC FN_PREFIX(CryptonightWOW_template_double_mainloop) +PUBLIC FN_PREFIX(CryptonightWOW_template_double_part2) +PUBLIC FN_PREFIX(CryptonightWOW_template_double_part3) +PUBLIC FN_PREFIX(CryptonightWOW_template_double_part4) +PUBLIC FN_PREFIX(CryptonightWOW_template_double_end) + +ALIGN(64) +FN_PREFIX(CryptonightWOW_template_part1): + mov QWORD PTR [rsp+16], rbx + mov QWORD PTR [rsp+24], rbp + mov QWORD PTR [rsp+32], rsi + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + push rdi + sub rsp, 64 + mov r12, rcx + mov r8, QWORD PTR [r12+32] + mov rdx, r12 + xor r8, QWORD PTR [r12] + mov r15, QWORD PTR [r12+40] + mov r9, r8 + xor r15, QWORD PTR [r12+8] + mov r11, QWORD PTR [r12+224] + mov r12, QWORD PTR [r12+56] + xor r12, QWORD PTR [rdx+24] + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + movaps XMMWORD PTR [rsp+48], xmm6 + movd xmm0, r12 + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+16], xmm8 + movaps XMMWORD PTR [rsp], xmm9 + mov r12, QWORD PTR [rdx+88] + xor r12, QWORD PTR [rdx+72] + movd xmm6, rax + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm6, xmm0 + and r9d, 2097136 + movd xmm0, r12 + movd xmm7, rax + punpcklqdq xmm7, xmm0 + mov r10d, r9d + movd xmm9, rsp + mov rsp, r8 + mov r8d, 524288 + + mov ebx, [rdx+96] + mov esi, [rdx+100] + mov edi, [rdx+104] + mov ebp, [rdx+108] + + ALIGN(64) +FN_PREFIX(CryptonightWOW_template_mainloop): + movdqa xmm5, XMMWORD PTR [r9+r11] + movd xmm0, r15 + movd xmm4, rsp + punpcklqdq xmm4, xmm0 + lea rdx, QWORD PTR [r9+r11] + + aesenc xmm5, xmm4 + movd r10d, xmm5 + and r10d, 2097136 + + mov r12d, r9d + mov eax, r9d + xor r9d, 48 + xor r12d, 16 + xor eax, 32 + movdqu xmm0, XMMWORD PTR [r9+r11] + movdqu xmm2, XMMWORD PTR [r12+r11] + movdqu xmm1, XMMWORD PTR [rax+r11] + paddq xmm0, xmm7 + paddq xmm2, xmm6 + paddq xmm1, xmm4 + movdqu XMMWORD PTR [r12+r11], xmm0 + movd r12, xmm5 + movdqu XMMWORD PTR [rax+r11], xmm2 + movdqu XMMWORD PTR [r9+r11], xmm1 + + movdqa xmm0, xmm5 + pxor xmm0, xmm6 + movdqu XMMWORD PTR [rdx], xmm0 + + lea r13d, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or r13, rdx + + xor r13, QWORD PTR [r10+r11] + mov r14, QWORD PTR [r10+r11+8] + + movd eax, xmm6 + movd edx, xmm7 + pextrd r9d, xmm7, 2 + +FN_PREFIX(CryptonightWOW_template_part2): + mov rax, r13 + mul r12 + movd xmm0, rax + movd xmm3, rdx + punpcklqdq xmm3, xmm0 + + mov r9d, r10d + mov r12d, r10d + xor r9d, 16 + xor r12d, 32 + xor r10d, 48 + movdqa xmm1, XMMWORD PTR [r12+r11] + xor rdx, QWORD PTR [r12+r11] + xor rax, QWORD PTR [r11+r12+8] + movdqa xmm2, XMMWORD PTR [r9+r11] + pxor xmm3, xmm2 + paddq xmm7, XMMWORD PTR [r10+r11] + paddq xmm1, xmm4 + paddq xmm3, xmm6 + movdqu XMMWORD PTR [r9+r11], xmm7 + movdqu XMMWORD PTR [r12+r11], xmm3 + movdqu XMMWORD PTR [r10+r11], xmm1 + + movdqa xmm7, xmm6 + add r15, rax + add rsp, rdx + xor r10, 48 + mov QWORD PTR [r10+r11], rsp + xor rsp, r13 + mov r9d, esp + mov QWORD PTR [r10+r11+8], r15 + and r9d, 2097136 + xor r15, r14 + movdqa xmm6, xmm5 + dec r8d + jnz FN_PREFIX(CryptonightWOW_template_mainloop) + +FN_PREFIX(CryptonightWOW_template_part3): + movd rsp, xmm9 + + mov rbx, QWORD PTR [rsp+136] + mov rbp, QWORD PTR [rsp+144] + mov rsi, QWORD PTR [rsp+152] + movaps xmm6, XMMWORD PTR [rsp+48] + movaps xmm7, XMMWORD PTR [rsp+32] + movaps xmm8, XMMWORD PTR [rsp+16] + movaps xmm9, XMMWORD PTR [rsp] + add rsp, 64 + pop rdi + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + ret 0 +FN_PREFIX(CryptonightWOW_template_end): + +ALIGN(64) +FN_PREFIX(CryptonightWOW_template_double_part1): + mov QWORD PTR [rsp+24], rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 320 + mov r14, QWORD PTR [rcx+32] + mov r8, rcx + xor r14, QWORD PTR [rcx] + mov r12, QWORD PTR [rcx+40] + mov ebx, r14d + mov rsi, QWORD PTR [rcx+224] + and ebx, 2097136 + xor r12, QWORD PTR [rcx+8] + mov rcx, QWORD PTR [rcx+56] + xor rcx, QWORD PTR [r8+24] + mov rax, QWORD PTR [r8+48] + xor rax, QWORD PTR [r8+16] + mov r15, QWORD PTR [rdx+32] + xor r15, QWORD PTR [rdx] + movd xmm0, rcx + mov rcx, QWORD PTR [r8+88] + xor rcx, QWORD PTR [r8+72] + mov r13, QWORD PTR [rdx+40] + mov rdi, QWORD PTR [rdx+224] + xor r13, QWORD PTR [rdx+8] + movaps XMMWORD PTR [rsp+160], xmm6 + movaps XMMWORD PTR [rsp+176], xmm7 + movaps XMMWORD PTR [rsp+192], xmm8 + movaps XMMWORD PTR [rsp+208], xmm9 + movaps XMMWORD PTR [rsp+224], xmm10 + movaps XMMWORD PTR [rsp+240], xmm11 + movaps XMMWORD PTR [rsp+256], xmm12 + movaps XMMWORD PTR [rsp+272], xmm13 + movaps XMMWORD PTR [rsp+288], xmm14 + movaps XMMWORD PTR [rsp+304], xmm15 + movd xmm7, rax + mov rax, QWORD PTR [r8+80] + xor rax, QWORD PTR [r8+64] + + movaps xmm1, XMMWORD PTR [rdx+96] + movaps xmm2, XMMWORD PTR [r8+96] + movaps XMMWORD PTR [rsp], xmm1 + movaps XMMWORD PTR [rsp+16], xmm2 + + mov r8d, r15d + punpcklqdq xmm7, xmm0 + movd xmm0, rcx + mov rcx, QWORD PTR [rdx+56] + xor rcx, QWORD PTR [rdx+24] + movd xmm9, rax + mov QWORD PTR [rsp+128], rsi + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + punpcklqdq xmm9, xmm0 + movd xmm0, rcx + mov rcx, QWORD PTR [rdx+88] + xor rcx, QWORD PTR [rdx+72] + movd xmm8, rax + mov QWORD PTR [rsp+136], rdi + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm8, xmm0 + and r8d, 2097136 + movd xmm0, rcx + mov r11d, 524288 + movd xmm10, rax + punpcklqdq xmm10, xmm0 + + movd xmm14, QWORD PTR [rsp+128] + movd xmm15, QWORD PTR [rsp+136] + + ALIGN(64) +FN_PREFIX(CryptonightWOW_template_double_mainloop): + movdqu xmm6, XMMWORD PTR [rbx+rsi] + movd xmm0, r12 + mov ecx, ebx + movd xmm3, r14 + punpcklqdq xmm3, xmm0 + xor ebx, 16 + aesenc xmm6, xmm3 + movd rdx, xmm6 + movd xmm4, r15 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + xor ebx, 48 + paddq xmm0, xmm7 + movdqu xmm1, XMMWORD PTR [rbx+rsi] + movdqu XMMWORD PTR [rbx+rsi], xmm0 + paddq xmm1, xmm3 + xor ebx, 16 + mov eax, ebx + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + movdqu XMMWORD PTR [rbx+rsi], xmm1 + paddq xmm0, xmm9 + movdqu XMMWORD PTR [rax+rsi], xmm0 + movdqa xmm0, xmm6 + pxor xmm0, xmm7 + movdqu XMMWORD PTR [rcx+rsi], xmm0 + mov esi, edx + movdqu xmm5, XMMWORD PTR [r8+rdi] + and esi, 2097136 + mov ecx, r8d + movd xmm0, r13 + punpcklqdq xmm4, xmm0 + xor r8d, 16 + aesenc xmm5, xmm4 + movdqu xmm0, XMMWORD PTR [r8+rdi] + xor r8d, 48 + paddq xmm0, xmm8 + movdqu xmm1, XMMWORD PTR [r8+rdi] + movdqu XMMWORD PTR [r8+rdi], xmm0 + paddq xmm1, xmm4 + xor r8d, 16 + mov eax, r8d + xor rax, 32 + movdqu xmm0, XMMWORD PTR [r8+rdi] + movdqu XMMWORD PTR [r8+rdi], xmm1 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rdi], xmm0 + movdqa xmm0, xmm5 + pxor xmm0, xmm8 + movdqu XMMWORD PTR [rcx+rdi], xmm0 + movd rdi, xmm5 + movd rcx, xmm14 + mov ebp, edi + mov r8, QWORD PTR [rcx+rsi] + mov r10, QWORD PTR [rcx+rsi+8] + lea r9, QWORD PTR [rcx+rsi] + xor esi, 16 + + movd xmm0, rsp + movd xmm1, rsi + movd xmm2, rdi + movd xmm11, rbp + movd xmm12, r15 + movd xmm13, rdx + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp+16] + mov esi, DWORD PTR [rsp+20] + mov edi, DWORD PTR [rsp+24] + mov ebp, DWORD PTR [rsp+28] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + xor r8, rax + + movd esp, xmm3 + pextrd r15d, xmm3, 2 + movd eax, xmm7 + movd edx, xmm9 + pextrd r9d, xmm9, 2 + +FN_PREFIX(CryptonightWOW_template_double_part2): + + movd rsp, xmm0 + mov DWORD PTR [rsp+16], ebx + mov DWORD PTR [rsp+20], esi + mov DWORD PTR [rsp+24], edi + mov DWORD PTR [rsp+28], ebp + + movd rsi, xmm1 + movd rdi, xmm2 + movd rbp, xmm11 + movd r15, xmm12 + movd rdx, xmm13 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rbx, r8 + mov rax, r8 + mul rdx + and ebp, 2097136 + mov r8, rax + movd xmm1, rdx + movd xmm0, r8 + punpcklqdq xmm1, xmm0 + pxor xmm1, XMMWORD PTR [rcx+rsi] + xor esi, 48 + paddq xmm1, xmm7 + movdqu xmm2, XMMWORD PTR [rsi+rcx] + xor rdx, QWORD PTR [rsi+rcx] + paddq xmm2, xmm3 + xor r8, QWORD PTR [rsi+rcx+8] + movdqu XMMWORD PTR [rsi+rcx], xmm1 + xor esi, 16 + mov eax, esi + mov rsi, rcx + movdqu xmm0, XMMWORD PTR [rax+rcx] + movdqu XMMWORD PTR [rax+rcx], xmm2 + paddq xmm0, xmm9 + add r12, r8 + xor rax, 32 + add r14, rdx + movdqa xmm9, xmm7 + movdqa xmm7, xmm6 + movdqu XMMWORD PTR [rax+rcx], xmm0 + mov QWORD PTR [r9+8], r12 + xor r12, r10 + mov QWORD PTR [r9], r14 + movd rcx, xmm15 + xor r14, rbx + mov r10d, ebp + mov ebx, r14d + xor ebp, 16 + and ebx, 2097136 + mov r8, QWORD PTR [r10+rcx] + mov r9, QWORD PTR [r10+rcx+8] + + movd xmm0, rsp + movd xmm1, rbx + movd xmm2, rsi + movd xmm11, rdi + movd xmm12, rbp + movd xmm13, r15 + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp] + mov esi, DWORD PTR [rsp+4] + mov edi, DWORD PTR [rsp+8] + mov ebp, DWORD PTR [rsp+12] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + + xor r8, rax + movd xmm3, r8 + + movd esp, xmm4 + pextrd r15d, xmm4, 2 + movd eax, xmm8 + movd edx, xmm10 + pextrd r9d, xmm10, 2 + +FN_PREFIX(CryptonightWOW_template_double_part3): + + movd rsp, xmm0 + mov DWORD PTR [rsp], ebx + mov DWORD PTR [rsp+4], esi + mov DWORD PTR [rsp+8], edi + mov DWORD PTR [rsp+12], ebp + + movd rbx, xmm1 + movd rsi, xmm2 + movd rdi, xmm11 + movd rbp, xmm12 + movd r15, xmm13 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rax, r8 + mul rdi + movd xmm1, rdx + movd xmm0, rax + punpcklqdq xmm1, xmm0 + mov rdi, rcx + mov r8, rax + pxor xmm1, XMMWORD PTR [rbp+rcx] + xor ebp, 48 + paddq xmm1, xmm8 + xor r8, QWORD PTR [rbp+rcx+8] + xor rdx, QWORD PTR [rbp+rcx] + add r13, r8 + movdqu xmm2, XMMWORD PTR [rbp+rcx] + add r15, rdx + movdqu XMMWORD PTR [rbp+rcx], xmm1 + paddq xmm2, xmm4 + xor ebp, 16 + mov eax, ebp + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbp+rcx] + movdqu XMMWORD PTR [rbp+rcx], xmm2 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rcx], xmm0 + movd rax, xmm3 + movdqa xmm10, xmm8 + mov QWORD PTR [r10+rcx], r15 + movdqa xmm8, xmm5 + xor r15, rax + mov QWORD PTR [r10+rcx+8], r13 + mov r8d, r15d + xor r13, r9 + and r8d, 2097136 + dec r11d + jnz FN_PREFIX(CryptonightWOW_template_double_mainloop) + +FN_PREFIX(CryptonightWOW_template_double_part4): + + mov rbx, QWORD PTR [rsp+400] + movaps xmm6, XMMWORD PTR [rsp+160] + movaps xmm7, XMMWORD PTR [rsp+176] + movaps xmm8, XMMWORD PTR [rsp+192] + movaps xmm9, XMMWORD PTR [rsp+208] + movaps xmm10, XMMWORD PTR [rsp+224] + movaps xmm11, XMMWORD PTR [rsp+240] + movaps xmm12, XMMWORD PTR [rsp+256] + movaps xmm13, XMMWORD PTR [rsp+272] + movaps xmm14, XMMWORD PTR [rsp+288] + movaps xmm15, XMMWORD PTR [rsp+304] + add rsp, 320 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + ret 0 +FN_PREFIX(CryptonightWOW_template_double_end): diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightWOW_template_win.inc b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightWOW_template_win.inc new file mode 100644 index 000000000..9db2cf397 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightWOW_template_win.inc @@ -0,0 +1,486 @@ +PUBLIC CryptonightWOW_template_part1 +PUBLIC CryptonightWOW_template_mainloop +PUBLIC CryptonightWOW_template_part2 +PUBLIC CryptonightWOW_template_part3 +PUBLIC CryptonightWOW_template_end +PUBLIC CryptonightWOW_template_double_part1 +PUBLIC CryptonightWOW_template_double_mainloop +PUBLIC CryptonightWOW_template_double_part2 +PUBLIC CryptonightWOW_template_double_part3 +PUBLIC CryptonightWOW_template_double_part4 +PUBLIC CryptonightWOW_template_double_end + +ALIGN(64) +CryptonightWOW_template_part1: + mov QWORD PTR [rsp+16], rbx + mov QWORD PTR [rsp+24], rbp + mov QWORD PTR [rsp+32], rsi + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + push rdi + sub rsp, 64 + mov r12, rcx + mov r8, QWORD PTR [r12+32] + mov rdx, r12 + xor r8, QWORD PTR [r12] + mov r15, QWORD PTR [r12+40] + mov r9, r8 + xor r15, QWORD PTR [r12+8] + mov r11, QWORD PTR [r12+224] + mov r12, QWORD PTR [r12+56] + xor r12, QWORD PTR [rdx+24] + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + movaps XMMWORD PTR [rsp+48], xmm6 + movd xmm0, r12 + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+16], xmm8 + movaps XMMWORD PTR [rsp], xmm9 + mov r12, QWORD PTR [rdx+88] + xor r12, QWORD PTR [rdx+72] + movd xmm6, rax + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm6, xmm0 + and r9d, 2097136 + movd xmm0, r12 + movd xmm7, rax + punpcklqdq xmm7, xmm0 + mov r10d, r9d + movd xmm9, rsp + mov rsp, r8 + mov r8d, 524288 + + mov ebx, [rdx+96] + mov esi, [rdx+100] + mov edi, [rdx+104] + mov ebp, [rdx+108] + + ALIGN(64) +CryptonightWOW_template_mainloop: + movdqa xmm5, XMMWORD PTR [r9+r11] + movd xmm0, r15 + movd xmm4, rsp + punpcklqdq xmm4, xmm0 + lea rdx, QWORD PTR [r9+r11] + + aesenc xmm5, xmm4 + movd r10d, xmm5 + and r10d, 2097136 + + mov r12d, r9d + mov eax, r9d + xor r9d, 48 + xor r12d, 16 + xor eax, 32 + movdqu xmm0, XMMWORD PTR [r9+r11] + movdqu xmm2, XMMWORD PTR [r12+r11] + movdqu xmm1, XMMWORD PTR [rax+r11] + paddq xmm0, xmm7 + paddq xmm2, xmm6 + paddq xmm1, xmm4 + movdqu XMMWORD PTR [r12+r11], xmm0 + movd r12, xmm5 + movdqu XMMWORD PTR [rax+r11], xmm2 + movdqu XMMWORD PTR [r9+r11], xmm1 + + movdqa xmm0, xmm5 + pxor xmm0, xmm6 + movdqu XMMWORD PTR [rdx], xmm0 + + lea r13d, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or r13, rdx + + xor r13, QWORD PTR [r10+r11] + mov r14, QWORD PTR [r10+r11+8] + + movd eax, xmm6 + movd edx, xmm7 + pextrd r9d, xmm7, 2 + +CryptonightWOW_template_part2: + mov rax, r13 + mul r12 + movd xmm0, rax + movd xmm3, rdx + punpcklqdq xmm3, xmm0 + + mov r9d, r10d + mov r12d, r10d + xor r9d, 16 + xor r12d, 32 + xor r10d, 48 + movdqa xmm1, XMMWORD PTR [r12+r11] + xor rdx, QWORD PTR [r12+r11] + xor rax, QWORD PTR [r11+r12+8] + movdqa xmm2, XMMWORD PTR [r9+r11] + pxor xmm3, xmm2 + paddq xmm7, XMMWORD PTR [r10+r11] + paddq xmm1, xmm4 + paddq xmm3, xmm6 + movdqu XMMWORD PTR [r9+r11], xmm7 + movdqu XMMWORD PTR [r12+r11], xmm3 + movdqu XMMWORD PTR [r10+r11], xmm1 + + movdqa xmm7, xmm6 + add r15, rax + add rsp, rdx + xor r10, 48 + mov QWORD PTR [r10+r11], rsp + xor rsp, r13 + mov r9d, esp + mov QWORD PTR [r10+r11+8], r15 + and r9d, 2097136 + xor r15, r14 + movdqa xmm6, xmm5 + dec r8d + jnz CryptonightWOW_template_mainloop + +CryptonightWOW_template_part3: + movd rsp, xmm9 + + mov rbx, QWORD PTR [rsp+136] + mov rbp, QWORD PTR [rsp+144] + mov rsi, QWORD PTR [rsp+152] + movaps xmm6, XMMWORD PTR [rsp+48] + movaps xmm7, XMMWORD PTR [rsp+32] + movaps xmm8, XMMWORD PTR [rsp+16] + movaps xmm9, XMMWORD PTR [rsp] + add rsp, 64 + pop rdi + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + ret 0 +CryptonightWOW_template_end: + +ALIGN(64) +CryptonightWOW_template_double_part1: + mov QWORD PTR [rsp+24], rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 320 + mov r14, QWORD PTR [rcx+32] + mov r8, rcx + xor r14, QWORD PTR [rcx] + mov r12, QWORD PTR [rcx+40] + mov ebx, r14d + mov rsi, QWORD PTR [rcx+224] + and ebx, 2097136 + xor r12, QWORD PTR [rcx+8] + mov rcx, QWORD PTR [rcx+56] + xor rcx, QWORD PTR [r8+24] + mov rax, QWORD PTR [r8+48] + xor rax, QWORD PTR [r8+16] + mov r15, QWORD PTR [rdx+32] + xor r15, QWORD PTR [rdx] + movd xmm0, rcx + mov rcx, QWORD PTR [r8+88] + xor rcx, QWORD PTR [r8+72] + mov r13, QWORD PTR [rdx+40] + mov rdi, QWORD PTR [rdx+224] + xor r13, QWORD PTR [rdx+8] + movaps XMMWORD PTR [rsp+160], xmm6 + movaps XMMWORD PTR [rsp+176], xmm7 + movaps XMMWORD PTR [rsp+192], xmm8 + movaps XMMWORD PTR [rsp+208], xmm9 + movaps XMMWORD PTR [rsp+224], xmm10 + movaps XMMWORD PTR [rsp+240], xmm11 + movaps XMMWORD PTR [rsp+256], xmm12 + movaps XMMWORD PTR [rsp+272], xmm13 + movaps XMMWORD PTR [rsp+288], xmm14 + movaps XMMWORD PTR [rsp+304], xmm15 + movd xmm7, rax + mov rax, QWORD PTR [r8+80] + xor rax, QWORD PTR [r8+64] + + movaps xmm1, XMMWORD PTR [rdx+96] + movaps xmm2, XMMWORD PTR [r8+96] + movaps XMMWORD PTR [rsp], xmm1 + movaps XMMWORD PTR [rsp+16], xmm2 + + mov r8d, r15d + punpcklqdq xmm7, xmm0 + movd xmm0, rcx + mov rcx, QWORD PTR [rdx+56] + xor rcx, QWORD PTR [rdx+24] + movd xmm9, rax + mov QWORD PTR [rsp+128], rsi + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + punpcklqdq xmm9, xmm0 + movd xmm0, rcx + mov rcx, QWORD PTR [rdx+88] + xor rcx, QWORD PTR [rdx+72] + movd xmm8, rax + mov QWORD PTR [rsp+136], rdi + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm8, xmm0 + and r8d, 2097136 + movd xmm0, rcx + mov r11d, 524288 + movd xmm10, rax + punpcklqdq xmm10, xmm0 + + movd xmm14, QWORD PTR [rsp+128] + movd xmm15, QWORD PTR [rsp+136] + + ALIGN(64) +CryptonightWOW_template_double_mainloop: + movdqu xmm6, XMMWORD PTR [rbx+rsi] + movd xmm0, r12 + mov ecx, ebx + movd xmm3, r14 + punpcklqdq xmm3, xmm0 + xor ebx, 16 + aesenc xmm6, xmm3 + movd rdx, xmm6 + movd xmm4, r15 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + xor ebx, 48 + paddq xmm0, xmm7 + movdqu xmm1, XMMWORD PTR [rbx+rsi] + movdqu XMMWORD PTR [rbx+rsi], xmm0 + paddq xmm1, xmm3 + xor ebx, 16 + mov eax, ebx + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + movdqu XMMWORD PTR [rbx+rsi], xmm1 + paddq xmm0, xmm9 + movdqu XMMWORD PTR [rax+rsi], xmm0 + movdqa xmm0, xmm6 + pxor xmm0, xmm7 + movdqu XMMWORD PTR [rcx+rsi], xmm0 + mov esi, edx + movdqu xmm5, XMMWORD PTR [r8+rdi] + and esi, 2097136 + mov ecx, r8d + movd xmm0, r13 + punpcklqdq xmm4, xmm0 + xor r8d, 16 + aesenc xmm5, xmm4 + movdqu xmm0, XMMWORD PTR [r8+rdi] + xor r8d, 48 + paddq xmm0, xmm8 + movdqu xmm1, XMMWORD PTR [r8+rdi] + movdqu XMMWORD PTR [r8+rdi], xmm0 + paddq xmm1, xmm4 + xor r8d, 16 + mov eax, r8d + xor rax, 32 + movdqu xmm0, XMMWORD PTR [r8+rdi] + movdqu XMMWORD PTR [r8+rdi], xmm1 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rdi], xmm0 + movdqa xmm0, xmm5 + pxor xmm0, xmm8 + movdqu XMMWORD PTR [rcx+rdi], xmm0 + movd rdi, xmm5 + movd rcx, xmm14 + mov ebp, edi + mov r8, QWORD PTR [rcx+rsi] + mov r10, QWORD PTR [rcx+rsi+8] + lea r9, QWORD PTR [rcx+rsi] + xor esi, 16 + + movd xmm0, rsp + movd xmm1, rsi + movd xmm2, rdi + movd xmm11, rbp + movd xmm12, r15 + movd xmm13, rdx + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp+16] + mov esi, DWORD PTR [rsp+20] + mov edi, DWORD PTR [rsp+24] + mov ebp, DWORD PTR [rsp+28] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + xor r8, rax + + movd esp, xmm3 + pextrd r15d, xmm3, 2 + movd eax, xmm7 + movd edx, xmm9 + pextrd r9d, xmm9, 2 + +CryptonightWOW_template_double_part2: + + movd rsp, xmm0 + mov DWORD PTR [rsp+16], ebx + mov DWORD PTR [rsp+20], esi + mov DWORD PTR [rsp+24], edi + mov DWORD PTR [rsp+28], ebp + + movd rsi, xmm1 + movd rdi, xmm2 + movd rbp, xmm11 + movd r15, xmm12 + movd rdx, xmm13 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rbx, r8 + mov rax, r8 + mul rdx + and ebp, 2097136 + mov r8, rax + movd xmm1, rdx + movd xmm0, r8 + punpcklqdq xmm1, xmm0 + pxor xmm1, XMMWORD PTR [rcx+rsi] + xor esi, 48 + paddq xmm1, xmm7 + movdqu xmm2, XMMWORD PTR [rsi+rcx] + xor rdx, QWORD PTR [rsi+rcx] + paddq xmm2, xmm3 + xor r8, QWORD PTR [rsi+rcx+8] + movdqu XMMWORD PTR [rsi+rcx], xmm1 + xor esi, 16 + mov eax, esi + mov rsi, rcx + movdqu xmm0, XMMWORD PTR [rax+rcx] + movdqu XMMWORD PTR [rax+rcx], xmm2 + paddq xmm0, xmm9 + add r12, r8 + xor rax, 32 + add r14, rdx + movdqa xmm9, xmm7 + movdqa xmm7, xmm6 + movdqu XMMWORD PTR [rax+rcx], xmm0 + mov QWORD PTR [r9+8], r12 + xor r12, r10 + mov QWORD PTR [r9], r14 + movd rcx, xmm15 + xor r14, rbx + mov r10d, ebp + mov ebx, r14d + xor ebp, 16 + and ebx, 2097136 + mov r8, QWORD PTR [r10+rcx] + mov r9, QWORD PTR [r10+rcx+8] + + movd xmm0, rsp + movd xmm1, rbx + movd xmm2, rsi + movd xmm11, rdi + movd xmm12, rbp + movd xmm13, r15 + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp] + mov esi, DWORD PTR [rsp+4] + mov edi, DWORD PTR [rsp+8] + mov ebp, DWORD PTR [rsp+12] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + + xor r8, rax + movd xmm3, r8 + + movd esp, xmm4 + pextrd r15d, xmm4, 2 + movd eax, xmm8 + movd edx, xmm10 + pextrd r9d, xmm10, 2 + +CryptonightWOW_template_double_part3: + + movd rsp, xmm0 + mov DWORD PTR [rsp], ebx + mov DWORD PTR [rsp+4], esi + mov DWORD PTR [rsp+8], edi + mov DWORD PTR [rsp+12], ebp + + movd rbx, xmm1 + movd rsi, xmm2 + movd rdi, xmm11 + movd rbp, xmm12 + movd r15, xmm13 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rax, r8 + mul rdi + movd xmm1, rdx + movd xmm0, rax + punpcklqdq xmm1, xmm0 + mov rdi, rcx + mov r8, rax + pxor xmm1, XMMWORD PTR [rbp+rcx] + xor ebp, 48 + paddq xmm1, xmm8 + xor r8, QWORD PTR [rbp+rcx+8] + xor rdx, QWORD PTR [rbp+rcx] + add r13, r8 + movdqu xmm2, XMMWORD PTR [rbp+rcx] + add r15, rdx + movdqu XMMWORD PTR [rbp+rcx], xmm1 + paddq xmm2, xmm4 + xor ebp, 16 + mov eax, ebp + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbp+rcx] + movdqu XMMWORD PTR [rbp+rcx], xmm2 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rcx], xmm0 + movd rax, xmm3 + movdqa xmm10, xmm8 + mov QWORD PTR [r10+rcx], r15 + movdqa xmm8, xmm5 + xor r15, rax + mov QWORD PTR [r10+rcx+8], r13 + mov r8d, r15d + xor r13, r9 + and r8d, 2097136 + dec r11d + jnz CryptonightWOW_template_double_mainloop + +CryptonightWOW_template_double_part4: + + mov rbx, QWORD PTR [rsp+400] + movaps xmm6, XMMWORD PTR [rsp+160] + movaps xmm7, XMMWORD PTR [rsp+176] + movaps xmm8, XMMWORD PTR [rsp+192] + movaps xmm9, XMMWORD PTR [rsp+208] + movaps xmm10, XMMWORD PTR [rsp+224] + movaps xmm11, XMMWORD PTR [rsp+240] + movaps xmm12, XMMWORD PTR [rsp+256] + movaps xmm13, XMMWORD PTR [rsp+272] + movaps xmm14, XMMWORD PTR [rsp+288] + movaps xmm15, XMMWORD PTR [rsp+304] + add rsp, 320 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + ret 0 +CryptonightWOW_template_double_end: diff --git a/src/Native/libcryptonight/crypto/asm/win64/cnv2_double_main_loop_sandybridge.inc b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_double_main_loop_sandybridge.inc similarity index 99% rename from src/Native/libcryptonight/crypto/asm/win64/cnv2_double_main_loop_sandybridge.inc rename to src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_double_main_loop_sandybridge.inc index 44ea89230..05af93934 100644 --- a/src/Native/libcryptonight/crypto/asm/win64/cnv2_double_main_loop_sandybridge.inc +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_double_main_loop_sandybridge.inc @@ -94,7 +94,7 @@ lea r9, QWORD PTR [rdx+r13] movdqu xmm15, XMMWORD PTR [r9] - ALIGN 16 + ALIGN(64) main_loop_double_sandybridge: movdqu xmm9, xmm15 mov eax, edx diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_main_loop_bulldozer.inc b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_main_loop_bulldozer.inc new file mode 100644 index 000000000..03a36f48d --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_main_loop_bulldozer.inc @@ -0,0 +1,180 @@ + mov QWORD PTR [rsp+16], rbx + mov QWORD PTR [rsp+24], rbp + mov QWORD PTR [rsp+32], rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 64 + + stmxcsr DWORD PTR [rsp] + mov DWORD PTR [rsp+4], 24448 + ldmxcsr DWORD PTR [rsp+4] + + mov rax, QWORD PTR [rcx+48] + mov r9, rcx + xor rax, QWORD PTR [rcx+16] + mov ebp, 524288 + mov r8, QWORD PTR [rcx+32] + xor r8, QWORD PTR [rcx] + mov r11, QWORD PTR [rcx+40] + mov r10, r8 + mov rdx, QWORD PTR [rcx+56] + movd xmm3, rax + xor rdx, QWORD PTR [rcx+24] + xor r11, QWORD PTR [rcx+8] + mov rbx, QWORD PTR [rcx+224] + mov rax, QWORD PTR [r9+80] + xor rax, QWORD PTR [r9+64] + movd xmm0, rdx + mov rcx, QWORD PTR [rcx+88] + xor rcx, QWORD PTR [r9+72] + mov rdi, QWORD PTR [r9+104] + and r10d, 2097136 + movaps XMMWORD PTR [rsp+48], xmm6 + movd xmm4, rax + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+16], xmm8 + xorps xmm8, xmm8 + mov ax, 1023 + shl rax, 52 + movd xmm7, rax + mov r15, QWORD PTR [r9+96] + punpcklqdq xmm3, xmm0 + movd xmm0, rcx + punpcklqdq xmm4, xmm0 + + ALIGN(64) +cnv2_main_loop_bulldozer: + movdqa xmm5, XMMWORD PTR [r10+rbx] + movd xmm6, r8 + pinsrq xmm6, r11, 1 + lea rdx, QWORD PTR [r10+rbx] + lea r9, QWORD PTR [rdi+rdi] + shl rdi, 32 + + mov ecx, r10d + mov eax, r10d + xor ecx, 16 + xor eax, 32 + xor r10d, 48 + aesenc xmm5, xmm6 + movdqa xmm2, XMMWORD PTR [rcx+rbx] + movdqa xmm1, XMMWORD PTR [rax+rbx] + movdqa xmm0, XMMWORD PTR [r10+rbx] + paddq xmm2, xmm3 + paddq xmm1, xmm6 + paddq xmm0, xmm4 + movdqa XMMWORD PTR [rcx+rbx], xmm0 + movdqa XMMWORD PTR [rax+rbx], xmm2 + movdqa XMMWORD PTR [r10+rbx], xmm1 + + movaps xmm1, xmm8 + mov rsi, r15 + xor rsi, rdi + + mov edi, 1023 + shl rdi, 52 + + movd r14, xmm5 + pextrq rax, xmm5, 1 + + movdqa xmm0, xmm5 + pxor xmm0, xmm3 + mov r10, r14 + and r10d, 2097136 + movdqa XMMWORD PTR [rdx], xmm0 + xor rsi, QWORD PTR [r10+rbx] + lea r12, QWORD PTR [r10+rbx] + mov r13, QWORD PTR [r10+rbx+8] + + add r9d, r14d + or r9d, -2147483647 + xor edx, edx + div r9 + mov eax, eax + shl rdx, 32 + lea r15, [rax+rdx] + lea rax, [r14+r15] + shr rax, 12 + add rax, rdi + movd xmm0, rax + sqrtsd xmm1, xmm0 + movd rdi, xmm1 + test rdi, 524287 + je sqrt_fixup_bulldozer + shr rdi, 19 + +sqrt_fixup_bulldozer_ret: + mov rax, rsi + mul r14 + movd xmm1, rax + movd xmm0, rdx + punpcklqdq xmm0, xmm1 + + mov r9d, r10d + mov ecx, r10d + xor r9d, 16 + xor ecx, 32 + xor r10d, 48 + movdqa xmm1, XMMWORD PTR [rcx+rbx] + xor rdx, [rcx+rbx] + xor rax, [rcx+rbx+8] + movdqa xmm2, XMMWORD PTR [r9+rbx] + pxor xmm2, xmm0 + paddq xmm4, XMMWORD PTR [r10+rbx] + paddq xmm2, xmm3 + paddq xmm1, xmm6 + movdqa XMMWORD PTR [r9+rbx], xmm4 + movdqa XMMWORD PTR [rcx+rbx], xmm2 + movdqa XMMWORD PTR [r10+rbx], xmm1 + + movdqa xmm4, xmm3 + add r8, rdx + add r11, rax + mov QWORD PTR [r12], r8 + xor r8, rsi + mov QWORD PTR [r12+8], r11 + mov r10, r8 + xor r11, r13 + and r10d, 2097136 + movdqa xmm3, xmm5 + dec ebp + jne cnv2_main_loop_bulldozer + + ldmxcsr DWORD PTR [rsp] + movaps xmm6, XMMWORD PTR [rsp+48] + lea r11, QWORD PTR [rsp+64] + mov rbx, QWORD PTR [r11+56] + mov rbp, QWORD PTR [r11+64] + mov rsi, QWORD PTR [r11+72] + movaps xmm8, XMMWORD PTR [r11-48] + movaps xmm7, XMMWORD PTR [rsp+32] + mov rsp, r11 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + jmp cnv2_main_loop_bulldozer_endp + +sqrt_fixup_bulldozer: + movd r9, xmm5 + add r9, r15 + dec rdi + mov edx, -1022 + shl rdx, 32 + mov rax, rdi + shr rdi, 19 + shr rax, 20 + mov rcx, rdi + sub rcx, rax + lea rcx, [rcx+rdx+1] + add rax, rdx + imul rcx, rax + sub rcx, r9 + adc rdi, 0 + jmp sqrt_fixup_bulldozer_ret + +cnv2_main_loop_bulldozer_endp: diff --git a/src/Native/libcryptonight/crypto/asm/win64/cnv2_main_loop_ivybridge.inc b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_main_loop_ivybridge.inc similarity index 99% rename from src/Native/libcryptonight/crypto/asm/win64/cnv2_main_loop_ivybridge.inc rename to src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_main_loop_ivybridge.inc index c925ca24c..77e28f801 100644 --- a/src/Native/libcryptonight/crypto/asm/win64/cnv2_main_loop_ivybridge.inc +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_main_loop_ivybridge.inc @@ -50,7 +50,7 @@ punpcklqdq xmm5, xmm0 movdqu xmm6, XMMWORD PTR [r10+rbx] - ALIGN 16 + ALIGN(64) main_loop_ivybridge: lea rdx, QWORD PTR [r10+rbx] mov ecx, r10d diff --git a/src/Native/libcryptonight/crypto/asm/win64/cnv2_main_loop_ryzen.inc b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_main_loop_ryzen.inc similarity index 99% rename from src/Native/libcryptonight/crypto/asm/win64/cnv2_main_loop_ryzen.inc rename to src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_main_loop_ryzen.inc index d1cd26c42..7e5c127f8 100644 --- a/src/Native/libcryptonight/crypto/asm/win64/cnv2_main_loop_ryzen.inc +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_main_loop_ryzen.inc @@ -45,7 +45,7 @@ movd xmm0, rcx punpcklqdq xmm4, xmm0 - ALIGN 16 + ALIGN(64) main_loop_ryzen: movdqa xmm5, XMMWORD PTR [r10+rbx] movd xmm0, r11 diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.S b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.S new file mode 100644 index 000000000..1200c4dfe --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.S @@ -0,0 +1,31 @@ +#define ALIGN(x) .align 64 +.intel_syntax noprefix +.section .text +.global cnv2_mainloop_ivybridge_asm +.global cnv2_mainloop_ryzen_asm +.global cnv2_mainloop_bulldozer_asm +.global cnv2_double_mainloop_sandybridge_asm + +ALIGN(64) +cnv2_mainloop_ivybridge_asm: + #include "../cn2/cnv2_main_loop_ivybridge.inc" + ret 0 + mov eax, 3735929054 + +ALIGN(64) +cnv2_mainloop_ryzen_asm: + #include "../cn2/cnv2_main_loop_ryzen.inc" + ret 0 + mov eax, 3735929054 + +ALIGN(64) +cnv2_mainloop_bulldozer_asm: + #include "../cn2/cnv2_main_loop_bulldozer.inc" + ret 0 + mov eax, 3735929054 + +ALIGN(64) +cnv2_double_mainloop_sandybridge_asm: + #include "../cn2/cnv2_double_main_loop_sandybridge.inc" + ret 0 + mov eax, 3735929054 diff --git a/src/Native/libcryptonight/crypto/asm/win64/cnv2_main_loop.asm b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.asm similarity index 54% rename from src/Native/libcryptonight/crypto/asm/win64/cnv2_main_loop.asm rename to src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.asm index d95222675..846b860c8 100644 --- a/src/Native/libcryptonight/crypto/asm/win64/cnv2_main_loop.asm +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.asm @@ -1,24 +1,35 @@ _TEXT_CNV2_MAINLOOP SEGMENT PAGE READ EXECUTE PUBLIC cnv2_mainloop_ivybridge_asm PUBLIC cnv2_mainloop_ryzen_asm +PUBLIC cnv2_mainloop_bulldozer_asm PUBLIC cnv2_double_mainloop_sandybridge_asm ALIGN 64 cnv2_mainloop_ivybridge_asm PROC - INCLUDE cnv2_main_loop_ivybridge.inc + INCLUDE cn2/cnv2_main_loop_ivybridge.inc ret 0 + mov eax, 3735929054 cnv2_mainloop_ivybridge_asm ENDP ALIGN 64 cnv2_mainloop_ryzen_asm PROC - INCLUDE cnv2_main_loop_ryzen.inc + INCLUDE cn2/cnv2_main_loop_ryzen.inc ret 0 + mov eax, 3735929054 cnv2_mainloop_ryzen_asm ENDP +ALIGN 64 +cnv2_mainloop_bulldozer_asm PROC + INCLUDE cn2/cnv2_main_loop_bulldozer.inc + ret 0 + mov eax, 3735929054 +cnv2_mainloop_bulldozer_asm ENDP + ALIGN 64 cnv2_double_mainloop_sandybridge_asm PROC - INCLUDE cnv2_double_main_loop_sandybridge.inc + INCLUDE cn2/cnv2_double_main_loop_sandybridge.inc ret 0 + mov eax, 3735929054 cnv2_double_mainloop_sandybridge_asm ENDP _TEXT_CNV2_MAINLOOP ENDS diff --git a/src/Native/libcryptonight/crypto/c_blake256.c b/src/Native/libcryptonight/xmrig/crypto/c_blake256.c similarity index 100% rename from src/Native/libcryptonight/crypto/c_blake256.c rename to src/Native/libcryptonight/xmrig/crypto/c_blake256.c diff --git a/src/Native/libcryptonight/crypto/c_blake256.h b/src/Native/libcryptonight/xmrig/crypto/c_blake256.h similarity index 94% rename from src/Native/libcryptonight/crypto/c_blake256.h rename to src/Native/libcryptonight/xmrig/crypto/c_blake256.h index 989dc6364..b9c2aad0d 100644 --- a/src/Native/libcryptonight/crypto/c_blake256.h +++ b/src/Native/libcryptonight/xmrig/crypto/c_blake256.h @@ -14,10 +14,6 @@ typedef struct { state outer; } hmac_state; -#ifdef __cplusplus -extern "C" { -#endif - void blake256_init(state *); void blake224_init(state *); @@ -44,8 +40,4 @@ void hmac_blake224_final(hmac_state *, uint8_t *); void hmac_blake256_hash(uint8_t *, const uint8_t *, uint64_t, const uint8_t *, uint64_t); void hmac_blake224_hash(uint8_t *, const uint8_t *, uint64_t, const uint8_t *, uint64_t); -#ifdef __cplusplus -} -#endif - #endif /* _BLAKE256_H_ */ diff --git a/src/Native/libcryptonight/crypto/c_groestl.c b/src/Native/libcryptonight/xmrig/crypto/c_groestl.c similarity index 100% rename from src/Native/libcryptonight/crypto/c_groestl.c rename to src/Native/libcryptonight/xmrig/crypto/c_groestl.c diff --git a/src/Native/libcryptonight/crypto/c_groestl.h b/src/Native/libcryptonight/xmrig/crypto/c_groestl.h similarity index 89% rename from src/Native/libcryptonight/crypto/c_groestl.h rename to src/Native/libcryptonight/xmrig/crypto/c_groestl.h index b7fc85f2a..2b5133934 100644 --- a/src/Native/libcryptonight/crypto/c_groestl.h +++ b/src/Native/libcryptonight/xmrig/crypto/c_groestl.h @@ -4,10 +4,10 @@ #include "crypto_uint8.h" #include "crypto_uint32.h" #include "crypto_uint64.h" -#include "crypto_hash.h" +#include "crypto_hash.h" -typedef crypto_uint8 uint8_t; -typedef crypto_uint32 uint32_t; +typedef crypto_uint8 uint8_t; +typedef crypto_uint32 uint32_t; typedef crypto_uint64 uint64_t; */ #include @@ -45,20 +45,12 @@ typedef struct { data buffer */ } groestlHashState; -#ifdef __cplusplus -extern "C" { -#endif - /*void Init(hashState*); void Update(hashState*, const BitSequence*, DataLength); void Final(hashState*, BitSequence*); */ void groestl(const BitSequence*, DataLength, BitSequence*); /* NIST API end */ -#ifdef __cplusplus -} -#endif - /* int crypto_hash(unsigned char *out, const unsigned char *in, diff --git a/src/Native/libcryptonight/crypto/c_jh.c b/src/Native/libcryptonight/xmrig/crypto/c_jh.c similarity index 100% rename from src/Native/libcryptonight/crypto/c_jh.c rename to src/Native/libcryptonight/xmrig/crypto/c_jh.c diff --git a/src/Native/libcryptonight/crypto/c_jh.h b/src/Native/libcryptonight/xmrig/crypto/c_jh.h similarity index 91% rename from src/Native/libcryptonight/crypto/c_jh.h rename to src/Native/libcryptonight/xmrig/crypto/c_jh.h index e9b77e2b2..d10d40fe5 100644 --- a/src/Native/libcryptonight/crypto/c_jh.h +++ b/src/Native/libcryptonight/xmrig/crypto/c_jh.h @@ -16,12 +16,4 @@ #include "hash.h" -#ifdef __cplusplus -extern "C" { -#endif - HashReturn jh_hash(int hashbitlen, const BitSequence *data, DataLength databitlen, BitSequence *hashval); - -#ifdef __cplusplus -} -#endif diff --git a/src/Native/libcryptonight/crypto/c_skein.c b/src/Native/libcryptonight/xmrig/crypto/c_skein.c similarity index 97% rename from src/Native/libcryptonight/crypto/c_skein.c rename to src/Native/libcryptonight/xmrig/crypto/c_skein.c index f218b164a..994e4d460 100644 --- a/src/Native/libcryptonight/crypto/c_skein.c +++ b/src/Native/libcryptonight/xmrig/crypto/c_skein.c @@ -5,7 +5,7 @@ ** Source code author: Doug Whiting, 2008. ** ** This algorithm and source code is released to the public domain. -** +** ************************************************************************/ #define SKEIN_PORT_CODE /* instantiate any code in skein_port.h */ @@ -47,9 +47,9 @@ typedef struct /* 512-bit Skein hash context stru } Skein_512_Ctxt_t; /* Skein APIs for (incremental) "straight hashing" */ -static SkeinHashReturn Skein_512_Init (Skein_512_Ctxt_t *ctx, size_t hashBitLen); -static SkeinHashReturn Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt); -static SkeinHashReturn Skein_512_Final (Skein_512_Ctxt_t *ctx, u08b_t * hashVal); +static int Skein_512_Init (Skein_512_Ctxt_t *ctx, size_t hashBitLen); +static int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt); +static int Skein_512_Final (Skein_512_Ctxt_t *ctx, u08b_t * hashVal); #ifndef SKEIN_TREE_HASH #define SKEIN_TREE_HASH (1) @@ -57,7 +57,7 @@ static SkeinHashReturn Skein_512_Final (Skein_512_Ctxt_t *ctx, u08b_t * hashVal /***************************************************************** ** "Internal" Skein definitions -** -- not needed for sequential hashing API, but will be +** -- not needed for sequential hashing API, but will be ** helpful for other uses of Skein (e.g., tree hash mode). ** -- included here so that they can be shared between ** reference and optimized code. @@ -179,11 +179,11 @@ static SkeinHashReturn Skein_512_Final (Skein_512_Ctxt_t *ctx, u08b_t * hashVal #define Skein_Assert(x,retCode)/* default: ignore all Asserts, for performance */ #define Skein_assert(x) #elif defined(SKEIN_ASSERT) -#include -#define Skein_Assert(x,retCode) assert(x) -#define Skein_assert(x) assert(x) +#include +#define Skein_Assert(x,retCode) assert(x) +#define Skein_assert(x) assert(x) #else -#include +#include #define Skein_Assert(x,retCode) { if (!(x)) return retCode; } /* caller error */ #define Skein_assert(x) assert(x) /* internal error */ #endif @@ -191,8 +191,8 @@ static SkeinHashReturn Skein_512_Final (Skein_512_Ctxt_t *ctx, u08b_t * hashVal /***************************************************************** ** Skein block function constants (shared across Ref and Opt code) ******************************************************************/ -enum -{ +enum +{ /* Skein_512 round rotation constants */ R_512_0_0=46, R_512_0_1=36, R_512_0_2=19, R_512_0_3=37, R_512_1_0=33, R_512_1_1=27, R_512_1_2=14, R_512_1_3=42, @@ -251,7 +251,7 @@ const u64b_t SKEIN_512_IV_256[] = #define BLK_BITS (WCNT*64) /* some useful definitions for code here */ #define KW_TWK_BASE (0) #define KW_KEY_BASE (3) -#define ks (kw + KW_KEY_BASE) +#define ks (kw + KW_KEY_BASE) #define ts (kw + KW_TWK_BASE) #ifdef SKEIN_DEBUG @@ -310,7 +310,7 @@ static void Skein_512_Process_Block(Skein_512_Ctxt_t *ctx,const u08b_t *blkPtr,s ks[5] = ctx->X[5]; ks[6] = ctx->X[6]; ks[7] = ctx->X[7]; - ks[8] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ + ks[8] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ ks[4] ^ ks[5] ^ ks[6] ^ ks[7] ^ SKEIN_KS_PARITY; ts[2] = ts[0] ^ ts[1]; @@ -338,7 +338,7 @@ static void Skein_512_Process_Block(Skein_512_Ctxt_t *ctx,const u08b_t *blkPtr,s X##p4 += X##p5; X##p5 = RotL_64(X##p5,ROT##_2); X##p5 ^= X##p4; \ X##p6 += X##p7; X##p7 = RotL_64(X##p7,ROT##_3); X##p7 ^= X##p6; \ -#if SKEIN_UNROLL_512 == 0 +#if SKEIN_UNROLL_512 == 0 #define R512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) /* unrolled */ \ Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rNum,Xptr); @@ -462,14 +462,14 @@ static void Skein_512_Process_Block(Skein_512_Ctxt_t *ctx,const u08b_t *blkPtr,s /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* init the context for a straight hashing operation */ -static SkeinHashReturn Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen) +static int Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen) { union { u08b_t b[SKEIN_512_STATE_BYTES]; u64b_t w[SKEIN_512_STATE_WORDS]; } cfg; /* config block */ - + Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ @@ -503,7 +503,7 @@ static SkeinHashReturn Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* process the input bytes */ -static SkeinHashReturn Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt) +static int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt) { size_t n; @@ -548,10 +548,10 @@ static SkeinHashReturn Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg return SKEIN_SUCCESS; } - + /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* finalize the hash computation and output the result */ -static SkeinHashReturn Skein_512_Final(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) +static int Skein_512_Final(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) { size_t i,n,byteCnt; u64b_t X[SKEIN_512_STATE_WORDS]; @@ -562,7 +562,7 @@ static SkeinHashReturn Skein_512_Final(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt); Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ - + /* now output the result */ byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ diff --git a/src/Native/libcryptonight/crypto/c_skein.h b/src/Native/libcryptonight/xmrig/crypto/c_skein.h similarity index 95% rename from src/Native/libcryptonight/crypto/c_skein.h rename to src/Native/libcryptonight/xmrig/crypto/c_skein.h index 4c618f60c..c642e265c 100644 --- a/src/Native/libcryptonight/crypto/c_skein.h +++ b/src/Native/libcryptonight/xmrig/crypto/c_skein.h @@ -9,7 +9,7 @@ ** This algorithm and source code is released to the public domain. ** *************************************************************************** -** +** ** The following compile-time switches may be defined to control some ** tradeoffs between speed, code size, error checking, and security. ** @@ -20,8 +20,8 @@ ** [default: no callouts (no overhead)] ** ** SKEIN_ERR_CHECK -- how error checking is handled inside Skein -** code. If not defined, most error checking -** is disabled (for performance). Otherwise, +** code. If not defined, most error checking +** is disabled (for performance). Otherwise, ** the switch value is interpreted as: ** 0: use assert() to flag errors ** 1: return SKEIN_FAIL to flag errors @@ -40,18 +40,10 @@ SkeinHashReturn; typedef size_t SkeinDataLength; /* bit count type */ typedef u08b_t SkeinBitSequence; /* bit stream type */ -#ifdef __cplusplus -extern "C" { -#endif - /* "all-in-one" call */ SkeinHashReturn skein_hash(int hashbitlen, const SkeinBitSequence *data, SkeinDataLength databitlen, SkeinBitSequence *hashval); void xmr_skein(const SkeinBitSequence *data, SkeinBitSequence *hashval); -#ifdef __cplusplus -} -#endif - #endif /* ifndef _SKEIN_H_ */ diff --git a/src/Native/libcryptonight/xmrig/crypto/cn_gpu_arm.cpp b/src/Native/libcryptonight/xmrig/crypto/cn_gpu_arm.cpp new file mode 100644 index 000000000..b463dd2ec --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/cn_gpu_arm.cpp @@ -0,0 +1,240 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "crypto/CryptoNight_constants.h" + + +inline void vandq_f32(float32x4_t &v, uint32_t v2) +{ + uint32x4_t vc = vdupq_n_u32(v2); + v = (float32x4_t)vandq_u32((uint32x4_t)v, vc); +} + + +inline void vorq_f32(float32x4_t &v, uint32_t v2) +{ + uint32x4_t vc = vdupq_n_u32(v2); + v = (float32x4_t)vorrq_u32((uint32x4_t)v, vc); +} + + +template +inline void vrot_si32(int32x4_t &r) +{ + r = (int32x4_t)vextq_s8((int8x16_t)r, (int8x16_t)r, v); +} + +template <> +inline void vrot_si32<0>(int32x4_t &r) +{ +} + + +inline uint32_t vheor_s32(const int32x4_t &v) +{ + int32x4_t v0 = veorq_s32(v, vrev64q_s32(v)); + int32x2_t vf = veor_s32(vget_high_s32(v0), vget_low_s32(v0)); + return (uint32_t)vget_lane_s32(vf, 0); +} + + +inline void prep_dv(int32_t *idx, int32x4_t &v, float32x4_t &n) +{ + v = vld1q_s32(idx); + n = vcvtq_f32_s32(v); +} + + +inline void sub_round(const float32x4_t &n0, const float32x4_t &n1, const float32x4_t &n2, const float32x4_t &n3, const float32x4_t &rnd_c, float32x4_t &n, float32x4_t &d, float32x4_t &c) +{ + float32x4_t ln1 = vaddq_f32(n1, c); + float32x4_t nn = vmulq_f32(n0, c); + nn = vmulq_f32(ln1, vmulq_f32(nn, nn)); + vandq_f32(nn, 0xFEFFFFFF); + vorq_f32(nn, 0x00800000); + n = vaddq_f32(n, nn); + + float32x4_t ln3 = vsubq_f32(n3, c); + float32x4_t dd = vmulq_f32(n2, c); + dd = vmulq_f32(ln3, vmulq_f32(dd, dd)); + vandq_f32(dd, 0xFEFFFFFF); + vorq_f32(dd, 0x00800000); + d = vaddq_f32(d, dd); + + //Constant feedback + c = vaddq_f32(c, rnd_c); + c = vaddq_f32(c, vdupq_n_f32(0.734375f)); + float32x4_t r = vaddq_f32(nn, dd); + vandq_f32(r, 0x807FFFFF); + vorq_f32(r, 0x40000000); + c = vaddq_f32(c, r); +} + + +inline void round_compute(const float32x4_t &n0, const float32x4_t &n1, const float32x4_t &n2, const float32x4_t &n3, const float32x4_t &rnd_c, float32x4_t &c, float32x4_t &r) +{ + float32x4_t n = vdupq_n_f32(0.0f), d = vdupq_n_f32(0.0f); + + sub_round(n0, n1, n2, n3, rnd_c, n, d, c); + sub_round(n1, n2, n3, n0, rnd_c, n, d, c); + sub_round(n2, n3, n0, n1, rnd_c, n, d, c); + sub_round(n3, n0, n1, n2, rnd_c, n, d, c); + sub_round(n3, n2, n1, n0, rnd_c, n, d, c); + sub_round(n2, n1, n0, n3, rnd_c, n, d, c); + sub_round(n1, n0, n3, n2, rnd_c, n, d, c); + sub_round(n0, n3, n2, n1, rnd_c, n, d, c); + + // Make sure abs(d) > 2.0 - this prevents division by zero and accidental overflows by division by < 1.0 + vandq_f32(d, 0xFF7FFFFF); + vorq_f32(d, 0x40000000); + r = vaddq_f32(r, vdivq_f32(n, d)); +} + + +// 112×4 = 448 +template +inline int32x4_t single_compute(const float32x4_t &n0, const float32x4_t &n1, const float32x4_t &n2, const float32x4_t &n3, float cnt, const float32x4_t &rnd_c, float32x4_t &sum) +{ + float32x4_t c = vdupq_n_f32(cnt); + float32x4_t r = vdupq_n_f32(0.0f); + + round_compute(n0, n1, n2, n3, rnd_c, c, r); + round_compute(n0, n1, n2, n3, rnd_c, c, r); + round_compute(n0, n1, n2, n3, rnd_c, c, r); + round_compute(n0, n1, n2, n3, rnd_c, c, r); + + // do a quick fmod by setting exp to 2 + vandq_f32(r, 0x807FFFFF); + vorq_f32(r, 0x40000000); + + if (add) { + sum = vaddq_f32(sum, r); + } else { + sum = r; + } + + const float32x4_t cc2 = vdupq_n_f32(536870880.0f); + r = vmulq_f32(r, cc2); // 35 + return vcvtq_s32_f32(r); +} + + +template +inline void single_compute_wrap(const float32x4_t &n0, const float32x4_t &n1, const float32x4_t &n2, const float32x4_t &n3, float cnt, const float32x4_t &rnd_c, float32x4_t &sum, int32x4_t &out) +{ + int32x4_t r = single_compute(n0, n1, n2, n3, cnt, rnd_c, sum); + vrot_si32(r); + out = veorq_s32(out, r); +} + + +template +inline int32_t *scratchpad_ptr(uint8_t* lpad, uint32_t idx, size_t n) { return reinterpret_cast(lpad + (idx & MASK) + n * 16); } + + +template +void cn_gpu_inner_arm(const uint8_t *spad, uint8_t *lpad) +{ + uint32_t s = reinterpret_cast(spad)[0] >> 8; + int32_t *idx0 = scratchpad_ptr(lpad, s, 0); + int32_t *idx1 = scratchpad_ptr(lpad, s, 1); + int32_t *idx2 = scratchpad_ptr(lpad, s, 2); + int32_t *idx3 = scratchpad_ptr(lpad, s, 3); + float32x4_t sum0 = vdupq_n_f32(0.0f); + + for (size_t i = 0; i < ITER; i++) { + float32x4_t n0, n1, n2, n3; + int32x4_t v0, v1, v2, v3; + float32x4_t suma, sumb, sum1, sum2, sum3; + + prep_dv(idx0, v0, n0); + prep_dv(idx1, v1, n1); + prep_dv(idx2, v2, n2); + prep_dv(idx3, v3, n3); + float32x4_t rc = sum0; + + int32x4_t out, out2; + out = vdupq_n_s32(0); + single_compute_wrap<0>(n0, n1, n2, n3, 1.3437500f, rc, suma, out); + single_compute_wrap<1>(n0, n2, n3, n1, 1.2812500f, rc, suma, out); + single_compute_wrap<2>(n0, n3, n1, n2, 1.3593750f, rc, sumb, out); + single_compute_wrap<3>(n0, n3, n2, n1, 1.3671875f, rc, sumb, out); + sum0 = vaddq_f32(suma, sumb); + vst1q_s32(idx0, veorq_s32(v0, out)); + out2 = out; + + out = vdupq_n_s32(0); + single_compute_wrap<0>(n1, n0, n2, n3, 1.4296875f, rc, suma, out); + single_compute_wrap<1>(n1, n2, n3, n0, 1.3984375f, rc, suma, out); + single_compute_wrap<2>(n1, n3, n0, n2, 1.3828125f, rc, sumb, out); + single_compute_wrap<3>(n1, n3, n2, n0, 1.3046875f, rc, sumb, out); + sum1 = vaddq_f32(suma, sumb); + vst1q_s32(idx1, veorq_s32(v1, out)); + out2 = veorq_s32(out2, out); + + out = vdupq_n_s32(0); + single_compute_wrap<0>(n2, n1, n0, n3, 1.4140625f, rc, suma, out); + single_compute_wrap<1>(n2, n0, n3, n1, 1.2734375f, rc, suma, out); + single_compute_wrap<2>(n2, n3, n1, n0, 1.2578125f, rc, sumb, out); + single_compute_wrap<3>(n2, n3, n0, n1, 1.2890625f, rc, sumb, out); + sum2 = vaddq_f32(suma, sumb); + vst1q_s32(idx2, veorq_s32(v2, out)); + out2 = veorq_s32(out2, out); + + out = vdupq_n_s32(0); + single_compute_wrap<0>(n3, n1, n2, n0, 1.3203125f, rc, suma, out); + single_compute_wrap<1>(n3, n2, n0, n1, 1.3515625f, rc, suma, out); + single_compute_wrap<2>(n3, n0, n1, n2, 1.3359375f, rc, sumb, out); + single_compute_wrap<3>(n3, n0, n2, n1, 1.4609375f, rc, sumb, out); + sum3 = vaddq_f32(suma, sumb); + vst1q_s32(idx3, veorq_s32(v3, out)); + out2 = veorq_s32(out2, out); + + sum0 = vaddq_f32(sum0, sum1); + sum2 = vaddq_f32(sum2, sum3); + sum0 = vaddq_f32(sum0, sum2); + + const float32x4_t cc1 = vdupq_n_f32(16777216.0f); + const float32x4_t cc2 = vdupq_n_f32(64.0f); + vandq_f32(sum0, 0x7fffffff); // take abs(va) by masking the float sign bit + // vs range 0 - 64 + n0 = vmulq_f32(sum0, cc1); + v0 = vcvtq_s32_f32(n0); + v0 = veorq_s32(v0, out2); + uint32_t n = vheor_s32(v0); + + // vs is now between 0 and 1 + sum0 = vdivq_f32(sum0, cc2); + idx0 = scratchpad_ptr(lpad, n, 0); + idx1 = scratchpad_ptr(lpad, n, 1); + idx2 = scratchpad_ptr(lpad, n, 2); + idx3 = scratchpad_ptr(lpad, n, 3); + } +} + +template void cn_gpu_inner_arm(const uint8_t* spad, uint8_t* lpad); diff --git a/src/Native/libcryptonight/xmrig/crypto/cn_gpu_avx.cpp b/src/Native/libcryptonight/xmrig/crypto/cn_gpu_avx.cpp new file mode 100644 index 000000000..3dc7cacb7 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/cn_gpu_avx.cpp @@ -0,0 +1,203 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "crypto/CryptoNight_constants.h" + +#ifdef __GNUC__ +# include +#else +# include +# define __restrict__ __restrict +#endif + +inline void prep_dv_avx(__m256i* idx, __m256i& v, __m256& n01) +{ + v = _mm256_load_si256(idx); + n01 = _mm256_cvtepi32_ps(v); +} + +inline __m256 fma_break(const __m256& x) +{ + // Break the dependency chain by setitng the exp to ?????01 + __m256 xx = _mm256_and_ps(_mm256_castsi256_ps(_mm256_set1_epi32(0xFEFFFFFF)), x); + return _mm256_or_ps(_mm256_castsi256_ps(_mm256_set1_epi32(0x00800000)), xx); +} + +// 14 +inline void sub_round(const __m256& n0, const __m256& n1, const __m256& n2, const __m256& n3, const __m256& rnd_c, __m256& n, __m256& d, __m256& c) +{ + __m256 nn = _mm256_mul_ps(n0, c); + nn = _mm256_mul_ps(_mm256_add_ps(n1, c), _mm256_mul_ps(nn, nn)); + nn = fma_break(nn); + n = _mm256_add_ps(n, nn); + + __m256 dd = _mm256_mul_ps(n2, c); + dd = _mm256_mul_ps(_mm256_sub_ps(n3, c), _mm256_mul_ps(dd, dd)); + dd = fma_break(dd); + d = _mm256_add_ps(d, dd); + + //Constant feedback + c = _mm256_add_ps(c, rnd_c); + c = _mm256_add_ps(c, _mm256_set1_ps(0.734375f)); + __m256 r = _mm256_add_ps(nn, dd); + r = _mm256_and_ps(_mm256_castsi256_ps(_mm256_set1_epi32(0x807FFFFF)), r); + r = _mm256_or_ps(_mm256_castsi256_ps(_mm256_set1_epi32(0x40000000)), r); + c = _mm256_add_ps(c, r); +} + +// 14*8 + 2 = 112 +inline void round_compute(const __m256& n0, const __m256& n1, const __m256& n2, const __m256& n3, const __m256& rnd_c, __m256& c, __m256& r) +{ + __m256 n = _mm256_setzero_ps(), d = _mm256_setzero_ps(); + + sub_round(n0, n1, n2, n3, rnd_c, n, d, c); + sub_round(n1, n2, n3, n0, rnd_c, n, d, c); + sub_round(n2, n3, n0, n1, rnd_c, n, d, c); + sub_round(n3, n0, n1, n2, rnd_c, n, d, c); + sub_round(n3, n2, n1, n0, rnd_c, n, d, c); + sub_round(n2, n1, n0, n3, rnd_c, n, d, c); + sub_round(n1, n0, n3, n2, rnd_c, n, d, c); + sub_round(n0, n3, n2, n1, rnd_c, n, d, c); + + // Make sure abs(d) > 2.0 - this prevents division by zero and accidental overflows by division by < 1.0 + d = _mm256_and_ps(_mm256_castsi256_ps(_mm256_set1_epi32(0xFF7FFFFF)), d); + d = _mm256_or_ps(_mm256_castsi256_ps(_mm256_set1_epi32(0x40000000)), d); + r = _mm256_add_ps(r, _mm256_div_ps(n, d)); +} + +// 112×4 = 448 +template +inline __m256i double_compute(const __m256& n0, const __m256& n1, const __m256& n2, const __m256& n3, + float lcnt, float hcnt, const __m256& rnd_c, __m256& sum) +{ + __m256 c = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_set1_ps(lcnt)), _mm_set1_ps(hcnt), 1); + __m256 r = _mm256_setzero_ps(); + + round_compute(n0, n1, n2, n3, rnd_c, c, r); + round_compute(n0, n1, n2, n3, rnd_c, c, r); + round_compute(n0, n1, n2, n3, rnd_c, c, r); + round_compute(n0, n1, n2, n3, rnd_c, c, r); + + // do a quick fmod by setting exp to 2 + r = _mm256_and_ps(_mm256_castsi256_ps(_mm256_set1_epi32(0x807FFFFF)), r); + r = _mm256_or_ps(_mm256_castsi256_ps(_mm256_set1_epi32(0x40000000)), r); + + if(add) + sum = _mm256_add_ps(sum, r); + else + sum = r; + + r = _mm256_mul_ps(r, _mm256_set1_ps(536870880.0f)); // 35 + return _mm256_cvttps_epi32(r); +} + +template +inline void double_compute_wrap(const __m256& n0, const __m256& n1, const __m256& n2, const __m256& n3, + float lcnt, float hcnt, const __m256& rnd_c, __m256& sum, __m256i& out) +{ + __m256i r = double_compute(n0, n1, n2, n3, lcnt, hcnt, rnd_c, sum); + if(rot != 0) + r = _mm256_or_si256(_mm256_bslli_epi128(r, 16 - rot), _mm256_bsrli_epi128(r, rot)); + + out = _mm256_xor_si256(out, r); +} + +template +inline __m256i* scratchpad_ptr(uint8_t* lpad, uint32_t idx, size_t n) { return reinterpret_cast<__m256i*>(lpad + (idx & MASK) + n*16); } + +template +void cn_gpu_inner_avx(const uint8_t* spad, uint8_t* lpad) +{ + uint32_t s = reinterpret_cast(spad)[0] >> 8; + __m256i* idx0 = scratchpad_ptr(lpad, s, 0); + __m256i* idx2 = scratchpad_ptr(lpad, s, 2); + __m256 sum0 = _mm256_setzero_ps(); + + for(size_t i = 0; i < ITER; i++) + { + __m256i v01, v23; + __m256 suma, sumb, sum1; + __m256 rc = sum0; + + __m256 n01, n23; + prep_dv_avx(idx0, v01, n01); + prep_dv_avx(idx2, v23, n23); + + __m256i out, out2; + __m256 n10, n22, n33; + n10 = _mm256_permute2f128_ps(n01, n01, 0x01); + n22 = _mm256_permute2f128_ps(n23, n23, 0x00); + n33 = _mm256_permute2f128_ps(n23, n23, 0x11); + + out = _mm256_setzero_si256(); + double_compute_wrap<0>(n01, n10, n22, n33, 1.3437500f, 1.4296875f, rc, suma, out); + double_compute_wrap<1>(n01, n22, n33, n10, 1.2812500f, 1.3984375f, rc, suma, out); + double_compute_wrap<2>(n01, n33, n10, n22, 1.3593750f, 1.3828125f, rc, sumb, out); + double_compute_wrap<3>(n01, n33, n22, n10, 1.3671875f, 1.3046875f, rc, sumb, out); + _mm256_store_si256(idx0, _mm256_xor_si256(v01, out)); + sum0 = _mm256_add_ps(suma, sumb); + out2 = out; + + __m256 n11, n02, n30; + n11 = _mm256_permute2f128_ps(n01, n01, 0x11); + n02 = _mm256_permute2f128_ps(n01, n23, 0x20); + n30 = _mm256_permute2f128_ps(n01, n23, 0x03); + + out = _mm256_setzero_si256(); + double_compute_wrap<0>(n23, n11, n02, n30, 1.4140625f, 1.3203125f, rc, suma, out); + double_compute_wrap<1>(n23, n02, n30, n11, 1.2734375f, 1.3515625f, rc, suma, out); + double_compute_wrap<2>(n23, n30, n11, n02, 1.2578125f, 1.3359375f, rc, sumb, out); + double_compute_wrap<3>(n23, n30, n02, n11, 1.2890625f, 1.4609375f, rc, sumb, out); + _mm256_store_si256(idx2, _mm256_xor_si256(v23, out)); + sum1 = _mm256_add_ps(suma, sumb); + + out2 = _mm256_xor_si256(out2, out); + out2 = _mm256_xor_si256(_mm256_permute2x128_si256(out2,out2,0x41), out2); + suma = _mm256_permute2f128_ps(sum0, sum1, 0x30); + sumb = _mm256_permute2f128_ps(sum0, sum1, 0x21); + sum0 = _mm256_add_ps(suma, sumb); + sum0 = _mm256_add_ps(sum0, _mm256_permute2f128_ps(sum0, sum0, 0x41)); + + // Clear the high 128 bits + __m128 sum = _mm256_castps256_ps128(sum0); + + sum = _mm_and_ps(_mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)), sum); // take abs(va) by masking the float sign bit + // vs range 0 - 64 + __m128i v0 = _mm_cvttps_epi32(_mm_mul_ps(sum, _mm_set1_ps(16777216.0f))); + v0 = _mm_xor_si128(v0, _mm256_castsi256_si128(out2)); + __m128i v1 = _mm_shuffle_epi32(v0, _MM_SHUFFLE(0, 1, 2, 3)); + v0 = _mm_xor_si128(v0, v1); + v1 = _mm_shuffle_epi32(v0, _MM_SHUFFLE(0, 1, 0, 1)); + v0 = _mm_xor_si128(v0, v1); + + // vs is now between 0 and 1 + sum = _mm_div_ps(sum, _mm_set1_ps(64.0f)); + sum0 = _mm256_insertf128_ps(_mm256_castps128_ps256(sum), sum, 1); + uint32_t n = _mm_cvtsi128_si32(v0); + idx0 = scratchpad_ptr(lpad, n, 0); + idx2 = scratchpad_ptr(lpad, n, 2); + } +} + +template void cn_gpu_inner_avx(const uint8_t* spad, uint8_t* lpad); diff --git a/src/Native/libcryptonight/xmrig/crypto/cn_gpu_ssse3.cpp b/src/Native/libcryptonight/xmrig/crypto/cn_gpu_ssse3.cpp new file mode 100644 index 000000000..ce3d19add --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/cn_gpu_ssse3.cpp @@ -0,0 +1,210 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "crypto/CryptoNight_constants.h" + +#ifdef __GNUC__ +# include +#else +# include +# define __restrict__ __restrict +#endif + +inline void prep_dv(__m128i* idx, __m128i& v, __m128& n) +{ + v = _mm_load_si128(idx); + n = _mm_cvtepi32_ps(v); +} + +inline __m128 fma_break(__m128 x) +{ + // Break the dependency chain by setitng the exp to ?????01 + x = _mm_and_ps(_mm_castsi128_ps(_mm_set1_epi32(0xFEFFFFFF)), x); + return _mm_or_ps(_mm_castsi128_ps(_mm_set1_epi32(0x00800000)), x); +} + +// 14 +inline void sub_round(__m128 n0, __m128 n1, __m128 n2, __m128 n3, __m128 rnd_c, __m128& n, __m128& d, __m128& c) +{ + n1 = _mm_add_ps(n1, c); + __m128 nn = _mm_mul_ps(n0, c); + nn = _mm_mul_ps(n1, _mm_mul_ps(nn,nn)); + nn = fma_break(nn); + n = _mm_add_ps(n, nn); + + n3 = _mm_sub_ps(n3, c); + __m128 dd = _mm_mul_ps(n2, c); + dd = _mm_mul_ps(n3, _mm_mul_ps(dd,dd)); + dd = fma_break(dd); + d = _mm_add_ps(d, dd); + + //Constant feedback + c = _mm_add_ps(c, rnd_c); + c = _mm_add_ps(c, _mm_set1_ps(0.734375f)); + __m128 r = _mm_add_ps(nn, dd); + r = _mm_and_ps(_mm_castsi128_ps(_mm_set1_epi32(0x807FFFFF)), r); + r = _mm_or_ps(_mm_castsi128_ps(_mm_set1_epi32(0x40000000)), r); + c = _mm_add_ps(c, r); +} + +// 14*8 + 2 = 112 +inline void round_compute(__m128 n0, __m128 n1, __m128 n2, __m128 n3, __m128 rnd_c, __m128& c, __m128& r) +{ + __m128 n = _mm_setzero_ps(), d = _mm_setzero_ps(); + + sub_round(n0, n1, n2, n3, rnd_c, n, d, c); + sub_round(n1, n2, n3, n0, rnd_c, n, d, c); + sub_round(n2, n3, n0, n1, rnd_c, n, d, c); + sub_round(n3, n0, n1, n2, rnd_c, n, d, c); + sub_round(n3, n2, n1, n0, rnd_c, n, d, c); + sub_round(n2, n1, n0, n3, rnd_c, n, d, c); + sub_round(n1, n0, n3, n2, rnd_c, n, d, c); + sub_round(n0, n3, n2, n1, rnd_c, n, d, c); + + // Make sure abs(d) > 2.0 - this prevents division by zero and accidental overflows by division by < 1.0 + d = _mm_and_ps(_mm_castsi128_ps(_mm_set1_epi32(0xFF7FFFFF)), d); + d = _mm_or_ps(_mm_castsi128_ps(_mm_set1_epi32(0x40000000)), d); + r =_mm_add_ps(r, _mm_div_ps(n,d)); +} + +// 112×4 = 448 +template +inline __m128i single_compute(__m128 n0, __m128 n1, __m128 n2, __m128 n3, float cnt, __m128 rnd_c, __m128& sum) +{ + __m128 c = _mm_set1_ps(cnt); + __m128 r = _mm_setzero_ps(); + + round_compute(n0, n1, n2, n3, rnd_c, c, r); + round_compute(n0, n1, n2, n3, rnd_c, c, r); + round_compute(n0, n1, n2, n3, rnd_c, c, r); + round_compute(n0, n1, n2, n3, rnd_c, c, r); + + // do a quick fmod by setting exp to 2 + r = _mm_and_ps(_mm_castsi128_ps(_mm_set1_epi32(0x807FFFFF)), r); + r = _mm_or_ps(_mm_castsi128_ps(_mm_set1_epi32(0x40000000)), r); + + if(add) + sum = _mm_add_ps(sum, r); + else + sum = r; + + r = _mm_mul_ps(r, _mm_set1_ps(536870880.0f)); // 35 + return _mm_cvttps_epi32(r); +} + +template +inline void single_compute_wrap(__m128 n0, __m128 n1, __m128 n2, __m128 n3, float cnt, __m128 rnd_c, __m128& sum, __m128i& out) +{ + __m128i r = single_compute(n0, n1, n2, n3, cnt, rnd_c, sum); + if(rot != 0) + r = _mm_or_si128(_mm_slli_si128(r, 16 - rot), _mm_srli_si128(r, rot)); + out = _mm_xor_si128(out, r); +} + +template +inline __m128i* scratchpad_ptr(uint8_t* lpad, uint32_t idx, size_t n) { return reinterpret_cast<__m128i*>(lpad + (idx & MASK) + n*16); } + +template +void cn_gpu_inner_ssse3(const uint8_t* spad, uint8_t* lpad) +{ + uint32_t s = reinterpret_cast(spad)[0] >> 8; + __m128i* idx0 = scratchpad_ptr(lpad, s, 0); + __m128i* idx1 = scratchpad_ptr(lpad, s, 1); + __m128i* idx2 = scratchpad_ptr(lpad, s, 2); + __m128i* idx3 = scratchpad_ptr(lpad, s, 3); + __m128 sum0 = _mm_setzero_ps(); + + for(size_t i = 0; i < ITER; i++) + { + __m128 n0, n1, n2, n3; + __m128i v0, v1, v2, v3; + __m128 suma, sumb, sum1, sum2, sum3; + + prep_dv(idx0, v0, n0); + prep_dv(idx1, v1, n1); + prep_dv(idx2, v2, n2); + prep_dv(idx3, v3, n3); + __m128 rc = sum0; + + __m128i out, out2; + out = _mm_setzero_si128(); + single_compute_wrap<0>(n0, n1, n2, n3, 1.3437500f, rc, suma, out); + single_compute_wrap<1>(n0, n2, n3, n1, 1.2812500f, rc, suma, out); + single_compute_wrap<2>(n0, n3, n1, n2, 1.3593750f, rc, sumb, out); + single_compute_wrap<3>(n0, n3, n2, n1, 1.3671875f, rc, sumb, out); + sum0 = _mm_add_ps(suma, sumb); + _mm_store_si128(idx0, _mm_xor_si128(v0, out)); + out2 = out; + + out = _mm_setzero_si128(); + single_compute_wrap<0>(n1, n0, n2, n3, 1.4296875f, rc, suma, out); + single_compute_wrap<1>(n1, n2, n3, n0, 1.3984375f, rc, suma, out); + single_compute_wrap<2>(n1, n3, n0, n2, 1.3828125f, rc, sumb, out); + single_compute_wrap<3>(n1, n3, n2, n0, 1.3046875f, rc, sumb, out); + sum1 = _mm_add_ps(suma, sumb); + _mm_store_si128(idx1, _mm_xor_si128(v1, out)); + out2 = _mm_xor_si128(out2, out); + + out = _mm_setzero_si128(); + single_compute_wrap<0>(n2, n1, n0, n3, 1.4140625f, rc, suma, out); + single_compute_wrap<1>(n2, n0, n3, n1, 1.2734375f, rc, suma, out); + single_compute_wrap<2>(n2, n3, n1, n0, 1.2578125f, rc, sumb, out); + single_compute_wrap<3>(n2, n3, n0, n1, 1.2890625f, rc, sumb, out); + sum2 = _mm_add_ps(suma, sumb); + _mm_store_si128(idx2, _mm_xor_si128(v2, out)); + out2 = _mm_xor_si128(out2, out); + + out = _mm_setzero_si128(); + single_compute_wrap<0>(n3, n1, n2, n0, 1.3203125f, rc, suma, out); + single_compute_wrap<1>(n3, n2, n0, n1, 1.3515625f, rc, suma, out); + single_compute_wrap<2>(n3, n0, n1, n2, 1.3359375f, rc, sumb, out); + single_compute_wrap<3>(n3, n0, n2, n1, 1.4609375f, rc, sumb, out); + sum3 = _mm_add_ps(suma, sumb); + _mm_store_si128(idx3, _mm_xor_si128(v3, out)); + out2 = _mm_xor_si128(out2, out); + sum0 = _mm_add_ps(sum0, sum1); + sum2 = _mm_add_ps(sum2, sum3); + sum0 = _mm_add_ps(sum0, sum2); + + sum0 = _mm_and_ps(_mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)), sum0); // take abs(va) by masking the float sign bit + // vs range 0 - 64 + n0 = _mm_mul_ps(sum0, _mm_set1_ps(16777216.0f)); + v0 = _mm_cvttps_epi32(n0); + v0 = _mm_xor_si128(v0, out2); + v1 = _mm_shuffle_epi32(v0, _MM_SHUFFLE(0, 1, 2, 3)); + v0 = _mm_xor_si128(v0, v1); + v1 = _mm_shuffle_epi32(v0, _MM_SHUFFLE(0, 1, 0, 1)); + v0 = _mm_xor_si128(v0, v1); + + // vs is now between 0 and 1 + sum0 = _mm_div_ps(sum0, _mm_set1_ps(64.0f)); + uint32_t n = _mm_cvtsi128_si32(v0); + idx0 = scratchpad_ptr(lpad, n, 0); + idx1 = scratchpad_ptr(lpad, n, 1); + idx2 = scratchpad_ptr(lpad, n, 2); + idx3 = scratchpad_ptr(lpad, n, 3); + } +} + +template void cn_gpu_inner_ssse3(const uint8_t* spad, uint8_t* lpad); diff --git a/src/Native/libcryptonight/crypto/groestl_tables.h b/src/Native/libcryptonight/xmrig/crypto/groestl_tables.h similarity index 100% rename from src/Native/libcryptonight/crypto/groestl_tables.h rename to src/Native/libcryptonight/xmrig/crypto/groestl_tables.h diff --git a/src/Native/libcryptonight/crypto/hash.h b/src/Native/libcryptonight/xmrig/crypto/hash.h similarity index 100% rename from src/Native/libcryptonight/crypto/hash.h rename to src/Native/libcryptonight/xmrig/crypto/hash.h diff --git a/src/Native/libcryptonight/crypto/skein_port.h b/src/Native/libcryptonight/xmrig/crypto/skein_port.h similarity index 100% rename from src/Native/libcryptonight/crypto/skein_port.h rename to src/Native/libcryptonight/xmrig/crypto/skein_port.h diff --git a/src/Native/libcryptonight/crypto/soft_aes.h b/src/Native/libcryptonight/xmrig/crypto/soft_aes.h similarity index 100% rename from src/Native/libcryptonight/crypto/soft_aes.h rename to src/Native/libcryptonight/xmrig/crypto/soft_aes.h diff --git a/src/Native/libcryptonight/xmrig/crypto/variant4_random_math.h b/src/Native/libcryptonight/xmrig/crypto/variant4_random_math.h new file mode 100644 index 000000000..1f3ea0ac3 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/variant4_random_math.h @@ -0,0 +1,448 @@ +#ifndef VARIANT4_RANDOM_MATH_H +#define VARIANT4_RANDOM_MATH_H + +extern "C" +{ + #include "c_blake256.h" +} + +enum V4_Settings +{ + // Generate code with minimal theoretical latency = 45 cycles, which is equivalent to 15 multiplications + TOTAL_LATENCY = 15 * 3, + + // Always generate at least 60 instructions + NUM_INSTRUCTIONS_MIN = 60, + + // Never generate more than 70 instructions (final RET instruction doesn't count here) + NUM_INSTRUCTIONS_MAX = 70, + + // Available ALUs for MUL + // Modern CPUs typically have only 1 ALU which can do multiplications + ALU_COUNT_MUL = 1, + + // Total available ALUs + // Modern CPUs have 4 ALUs, but we use only 3 because random math executes together with other main loop code + ALU_COUNT = 3, +}; + +enum V4_InstructionList +{ + MUL, // a*b + ADD, // a+b + C, C is an unsigned 32-bit constant + SUB, // a-b + ROR, // rotate right "a" by "b & 31" bits + ROL, // rotate left "a" by "b & 31" bits + XOR, // a^b + RET, // finish execution + V4_INSTRUCTION_COUNT = RET, +}; + +// V4_InstructionDefinition is used to generate code from random data +// Every random sequence of bytes is a valid code +// +// There are 9 registers in total: +// - 4 variable registers +// - 5 constant registers initialized from loop variables +// This is why dst_index is 2 bits +enum V4_InstructionDefinition +{ + V4_OPCODE_BITS = 3, + V4_DST_INDEX_BITS = 2, + V4_SRC_INDEX_BITS = 3, +}; + +struct V4_Instruction +{ + uint8_t opcode; + uint8_t dst_index; + uint8_t src_index; + uint32_t C; +}; + +#ifndef FORCEINLINE +#ifdef __GNUC__ +#define FORCEINLINE __attribute__((always_inline)) inline +#elif _MSC_VER +#define FORCEINLINE __forceinline +#else +#define FORCEINLINE inline +#endif +#endif + +#ifndef UNREACHABLE_CODE +#ifdef __GNUC__ +#define UNREACHABLE_CODE __builtin_unreachable() +#elif _MSC_VER +#define UNREACHABLE_CODE __assume(false) +#else +#define UNREACHABLE_CODE +#endif +#endif + +// Random math interpreter's loop is fully unrolled and inlined to achieve 100% branch prediction on CPU: +// every switch-case will point to the same destination on every iteration of Cryptonight main loop +// +// This is about as fast as it can get without using low-level machine code generation +template +static void v4_random_math(const struct V4_Instruction* code, v4_reg* r) +{ + enum + { + REG_BITS = sizeof(v4_reg) * 8, + }; + +#define V4_EXEC(i) \ + { \ + const struct V4_Instruction* op = code + i; \ + const v4_reg src = r[op->src_index]; \ + v4_reg* dst = r + op->dst_index; \ + switch (op->opcode) \ + { \ + case MUL: \ + *dst *= src; \ + break; \ + case ADD: \ + *dst += src + op->C; \ + break; \ + case SUB: \ + *dst -= src; \ + break; \ + case ROR: \ + { \ + const uint32_t shift = src % REG_BITS; \ + *dst = (*dst >> shift) | (*dst << ((REG_BITS - shift) % REG_BITS)); \ + } \ + break; \ + case ROL: \ + { \ + const uint32_t shift = src % REG_BITS; \ + *dst = (*dst << shift) | (*dst >> ((REG_BITS - shift) % REG_BITS)); \ + } \ + break; \ + case XOR: \ + *dst ^= src; \ + break; \ + case RET: \ + return; \ + default: \ + UNREACHABLE_CODE; \ + break; \ + } \ + } + +#define V4_EXEC_10(j) \ + V4_EXEC(j + 0) \ + V4_EXEC(j + 1) \ + V4_EXEC(j + 2) \ + V4_EXEC(j + 3) \ + V4_EXEC(j + 4) \ + V4_EXEC(j + 5) \ + V4_EXEC(j + 6) \ + V4_EXEC(j + 7) \ + V4_EXEC(j + 8) \ + V4_EXEC(j + 9) + + // Generated program can have 60 + a few more (usually 2-3) instructions to achieve required latency + // I've checked all block heights < 10,000,000 and here is the distribution of program sizes: + // + // 60 27960 + // 61 105054 + // 62 2452759 + // 63 5115997 + // 64 1022269 + // 65 1109635 + // 66 153145 + // 67 8550 + // 68 4529 + // 69 102 + + // Unroll 70 instructions here + V4_EXEC_10(0); // instructions 0-9 + V4_EXEC_10(10); // instructions 10-19 + V4_EXEC_10(20); // instructions 20-29 + V4_EXEC_10(30); // instructions 30-39 + V4_EXEC_10(40); // instructions 40-49 + V4_EXEC_10(50); // instructions 50-59 + V4_EXEC_10(60); // instructions 60-69 + +#undef V4_EXEC_10 +#undef V4_EXEC +} + +// If we don't have enough data available, generate more +static FORCEINLINE void check_data(size_t* data_index, const size_t bytes_needed, int8_t* data, const size_t data_size) +{ + if (*data_index + bytes_needed > data_size) + { + hash_extra_blake(data, data_size, (char*) data); + *data_index = 0; + } +} + +// Generates as many random math operations as possible with given latency and ALU restrictions +// "code" array must have space for NUM_INSTRUCTIONS_MAX+1 instructions +template +static int v4_random_math_init(struct V4_Instruction* code, const uint64_t height) +{ + // MUL is 3 cycles, 3-way addition and rotations are 2 cycles, SUB/XOR are 1 cycle + // These latencies match real-life instruction latencies for Intel CPUs starting from Sandy Bridge and up to Skylake/Coffee lake + // + // AMD Ryzen has the same latencies except 1-cycle ROR/ROL, so it'll be a bit faster than Intel Sandy Bridge and newer processors + // Surprisingly, Intel Nehalem also has 1-cycle ROR/ROL, so it'll also be faster than Intel Sandy Bridge and newer processors + // AMD Bulldozer has 4 cycles latency for MUL (slower than Intel) and 1 cycle for ROR/ROL (faster than Intel), so average performance will be the same + // Source: https://www.agner.org/optimize/instruction_tables.pdf + const int op_latency[V4_INSTRUCTION_COUNT] = { 3, 2, 1, 2, 2, 1 }; + + // Instruction latencies for theoretical ASIC implementation + const int asic_op_latency[V4_INSTRUCTION_COUNT] = { 3, 1, 1, 1, 1, 1 }; + + // Available ALUs for each instruction + const int op_ALUs[V4_INSTRUCTION_COUNT] = { ALU_COUNT_MUL, ALU_COUNT, ALU_COUNT, ALU_COUNT, ALU_COUNT, ALU_COUNT }; + + int8_t data[32]; + memset(data, 0, sizeof(data)); + uint64_t tmp = SWAP64LE(height); + memcpy(data, &tmp, sizeof(uint64_t)); + if (VARIANT == xmrig::VARIANT_4) + { + data[20] = -38; + } + + // Set data_index past the last byte in data + // to trigger full data update with blake hash + // before we start using it + size_t data_index = sizeof(data); + + int code_size; + + // There is a small chance (1.8%) that register R8 won't be used in the generated program + // So we keep track of it and try again if it's not used + bool r8_used; + do { + int latency[9]; + int asic_latency[9]; + + // Tracks previous instruction and value of the source operand for registers R0-R3 throughout code execution + // byte 0: current value of the destination register + // byte 1: instruction opcode + // byte 2: current value of the source register + // + // Registers R4-R8 are constant and are treated as having the same value because when we do + // the same operation twice with two constant source registers, it can be optimized into a single operation + uint32_t inst_data[9] = { 0, 1, 2, 3, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF }; + + bool alu_busy[TOTAL_LATENCY + 1][ALU_COUNT]; + bool is_rotation[V4_INSTRUCTION_COUNT]; + bool rotated[4]; + int rotate_count = 0; + + memset(latency, 0, sizeof(latency)); + memset(asic_latency, 0, sizeof(asic_latency)); + memset(alu_busy, 0, sizeof(alu_busy)); + memset(is_rotation, 0, sizeof(is_rotation)); + memset(rotated, 0, sizeof(rotated)); + is_rotation[ROR] = true; + is_rotation[ROL] = true; + + int num_retries = 0; + code_size = 0; + + int total_iterations = 0; + r8_used = (VARIANT == xmrig::VARIANT_WOW); + + // Generate random code to achieve minimal required latency for our abstract CPU + // Try to get this latency for all 4 registers + while (((latency[0] < TOTAL_LATENCY) || (latency[1] < TOTAL_LATENCY) || (latency[2] < TOTAL_LATENCY) || (latency[3] < TOTAL_LATENCY)) && (num_retries < 64)) + { + // Fail-safe to guarantee loop termination + ++total_iterations; + if (total_iterations > 256) + break; + + check_data(&data_index, 1, data, sizeof(data)); + + const uint8_t c = ((uint8_t*)data)[data_index++]; + + // MUL = opcodes 0-2 + // ADD = opcode 3 + // SUB = opcode 4 + // ROR/ROL = opcode 5, shift direction is selected randomly + // XOR = opcodes 6-7 + uint8_t opcode = c & ((1 << V4_OPCODE_BITS) - 1); + if (opcode == 5) + { + check_data(&data_index, 1, data, sizeof(data)); + opcode = (data[data_index++] >= 0) ? ROR : ROL; + } + else if (opcode >= 6) + { + opcode = XOR; + } + else + { + opcode = (opcode <= 2) ? MUL : (opcode - 2); + } + + uint8_t dst_index = (c >> V4_OPCODE_BITS) & ((1 << V4_DST_INDEX_BITS) - 1); + uint8_t src_index = (c >> (V4_OPCODE_BITS + V4_DST_INDEX_BITS)) & ((1 << V4_SRC_INDEX_BITS) - 1); + + const int a = dst_index; + int b = src_index; + + // Don't do ADD/SUB/XOR with the same register + if (((opcode == ADD) || (opcode == SUB) || (opcode == XOR)) && (a == b)) + { + // a is always < 4, so we don't need to check bounds here + b = (VARIANT == xmrig::VARIANT_WOW) ? (a + 4) : 8; + src_index = b; + } + + // Don't do rotation with the same destination twice because it's equal to a single rotation + if (is_rotation[opcode] && rotated[a]) + { + continue; + } + + // Don't do the same instruction (except MUL) with the same source value twice because all other cases can be optimized: + // 2xADD(a, b, C) = ADD(a, b*2, C1+C2), same for SUB and rotations + // 2xXOR(a, b) = NOP + if ((opcode != MUL) && ((inst_data[a] & 0xFFFF00) == (opcode << 8) + ((inst_data[b] & 255) << 16))) + { + continue; + } + + // Find which ALU is available (and when) for this instruction + int next_latency = (latency[a] > latency[b]) ? latency[a] : latency[b]; + int alu_index = -1; + while (next_latency < TOTAL_LATENCY) + { + for (int i = op_ALUs[opcode] - 1; i >= 0; --i) + { + if (!alu_busy[next_latency][i]) + { + // ADD is implemented as two 1-cycle instructions on a real CPU, so do an additional availability check + if ((opcode == ADD) && alu_busy[next_latency + 1][i]) + { + continue; + } + + // Rotation can only start when previous rotation is finished, so do an additional availability check + if (is_rotation[opcode] && (next_latency < rotate_count * op_latency[opcode])) + { + continue; + } + + alu_index = i; + break; + } + } + if (alu_index >= 0) + { + break; + } + ++next_latency; + } + + // Don't generate instructions that leave some register unchanged for more than 7 cycles + if (next_latency > latency[a] + 7) + { + continue; + } + + next_latency += op_latency[opcode]; + + if (next_latency <= TOTAL_LATENCY) + { + if (is_rotation[opcode]) + { + ++rotate_count; + } + + // Mark ALU as busy only for the first cycle when it starts executing the instruction because ALUs are fully pipelined + alu_busy[next_latency - op_latency[opcode]][alu_index] = true; + latency[a] = next_latency; + + // ASIC is supposed to have enough ALUs to run as many independent instructions per cycle as possible, so latency calculation for ASIC is simple + asic_latency[a] = ((asic_latency[a] > asic_latency[b]) ? asic_latency[a] : asic_latency[b]) + asic_op_latency[opcode]; + + rotated[a] = is_rotation[opcode]; + + inst_data[a] = code_size + (opcode << 8) + ((inst_data[b] & 255) << 16); + + code[code_size].opcode = opcode; + code[code_size].dst_index = dst_index; + code[code_size].src_index = src_index; + code[code_size].C = 0; + + if (src_index == 8) + { + r8_used = true; + } + + if (opcode == ADD) + { + // ADD instruction is implemented as two 1-cycle instructions on a real CPU, so mark ALU as busy for the next cycle too + alu_busy[next_latency - op_latency[opcode] + 1][alu_index] = true; + + // ADD instruction requires 4 more random bytes for 32-bit constant "C" in "a = a + b + C" + check_data(&data_index, sizeof(uint32_t), data, sizeof(data)); + uint32_t t; + memcpy(&t, data + data_index, sizeof(uint32_t)); + code[code_size].C = SWAP32LE(t); + data_index += sizeof(uint32_t); + } + + ++code_size; + if (code_size >= NUM_INSTRUCTIONS_MIN) + { + break; + } + } + else + { + ++num_retries; + } + } + + // ASIC has more execution resources and can extract as much parallelism from the code as possible + // We need to add a few more MUL and ROR instructions to achieve minimal required latency for ASIC + // Get this latency for at least 1 of the 4 registers + const int prev_code_size = code_size; + while ((code_size < NUM_INSTRUCTIONS_MAX) && (asic_latency[0] < TOTAL_LATENCY) && (asic_latency[1] < TOTAL_LATENCY) && (asic_latency[2] < TOTAL_LATENCY) && (asic_latency[3] < TOTAL_LATENCY)) + { + int min_idx = 0; + int max_idx = 0; + for (int i = 1; i < 4; ++i) + { + if (asic_latency[i] < asic_latency[min_idx]) min_idx = i; + if (asic_latency[i] > asic_latency[max_idx]) max_idx = i; + } + + const uint8_t pattern[3] = { ROR, MUL, MUL }; + const uint8_t opcode = pattern[(code_size - prev_code_size) % 3]; + latency[min_idx] = latency[max_idx] + op_latency[opcode]; + asic_latency[min_idx] = asic_latency[max_idx] + asic_op_latency[opcode]; + + code[code_size].opcode = opcode; + code[code_size].dst_index = min_idx; + code[code_size].src_index = max_idx; + code[code_size].C = 0; + ++code_size; + } + + // There is ~98.15% chance that loop condition is false, so this loop will execute only 1 iteration most of the time + // It never does more than 4 iterations for all block heights < 10,000,000 + } while (!r8_used || (code_size < NUM_INSTRUCTIONS_MIN) || (code_size > NUM_INSTRUCTIONS_MAX)); + + // It's guaranteed that NUM_INSTRUCTIONS_MIN <= code_size <= NUM_INSTRUCTIONS_MAX here + // Add final instruction to stop the interpreter + code[code_size].opcode = RET; + code[code_size].dst_index = 0; + code[code_size].src_index = 0; + code[code_size].C = 0; + + return code_size; +} + +#endif diff --git a/src/Native/libcryptonight/xmrig/extra.cpp b/src/Native/libcryptonight/xmrig/extra.cpp new file mode 100644 index 000000000..8a6636031 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/extra.cpp @@ -0,0 +1,119 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include // for memcpy +#include "extra.h" +#include "crypto/CryptoNight_constants.h" +#include "common/cpu/Cpu.h" +#include "Mem.h" + +#if !defined(__ARM_ARCH) && !defined(XMRIG_NO_ASM) +template +static void patchCode(T dst, U src, const uint32_t iterations, const uint32_t mask) +{ + const uint8_t* p = reinterpret_cast(src); + + // Workaround for Visual Studio placing trampoline in debug builds. +# if defined(_MSC_VER) + if (p[0] == 0xE9) { + p += *(int32_t*)(p + 1) + 5; + } +# endif + + size_t size = 0; + while (*(uint32_t*)(p + size) != 0xDEADC0DE) { + ++size; + } + size += sizeof(uint32_t); + + memcpy((void*) dst, (const void*) src, size); + + uint8_t* patched_data = reinterpret_cast(dst); + for (size_t i = 0; i + sizeof(uint32_t) <= size; ++i) { + switch (*(uint32_t*)(patched_data + i)) { + case xmrig::CRYPTONIGHT_ITER: + *(uint32_t*)(patched_data + i) = iterations; + break; + + case xmrig::CRYPTONIGHT_MASK: + *(uint32_t*)(patched_data + i) = mask; + break; + } + } +} + + +extern "C" void cnv2_mainloop_ivybridge_asm(cryptonight_ctx *ctx); +extern "C" void cnv2_mainloop_ryzen_asm(cryptonight_ctx *ctx); +extern "C" void cnv2_mainloop_bulldozer_asm(cryptonight_ctx *ctx); +extern "C" void cnv2_double_mainloop_sandybridge_asm(cryptonight_ctx *ctx0, cryptonight_ctx *ctx1); + + +xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_ivybridge_asm = nullptr; +xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_ryzen_asm = nullptr; +xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_bulldozer_asm = nullptr; +xmrig::CpuThread::cn_mainloop_double_fun cn_half_double_mainloop_sandybridge_asm = nullptr; + +xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_ivybridge_asm = nullptr; +xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_ryzen_asm = nullptr; +xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_bulldozer_asm = nullptr; +xmrig::CpuThread::cn_mainloop_double_fun cn_trtl_double_mainloop_sandybridge_asm = nullptr; + +void xmrig::CpuThread::patchAsmVariants() +{ + const int allocation_size = 65536; + uint8_t *base = static_cast(Mem::allocateExecutableMemory(allocation_size)); + + cn_half_mainloop_ivybridge_asm = reinterpret_cast (base + 0x0000); + cn_half_mainloop_ryzen_asm = reinterpret_cast (base + 0x1000); + cn_half_mainloop_bulldozer_asm = reinterpret_cast (base + 0x2000); + cn_half_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0x3000); + + cn_trtl_mainloop_ivybridge_asm = reinterpret_cast (base + 0x4000); + cn_trtl_mainloop_ryzen_asm = reinterpret_cast (base + 0x5000); + cn_trtl_mainloop_bulldozer_asm = reinterpret_cast (base + 0x6000); + cn_trtl_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0x7000); + + patchCode(cn_half_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); + patchCode(cn_half_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); + patchCode(cn_half_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); + patchCode(cn_half_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); + + patchCode(cn_trtl_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); + patchCode(cn_trtl_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); + patchCode(cn_trtl_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); + patchCode(cn_trtl_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); + + Mem::protectExecutableMemory(base, allocation_size); + Mem::flushInstructionCache(base, allocation_size); +} + +struct Static { + Static() { + xmrig::Cpu::init(); + xmrig::CpuThread::patchAsmVariants(); + } +} s; + +#endif diff --git a/src/Native/libcryptonight/crypto/Asm.h b/src/Native/libcryptonight/xmrig/extra.h similarity index 65% rename from src/Native/libcryptonight/crypto/Asm.h rename to src/Native/libcryptonight/xmrig/extra.h index 3b755fd64..f90b0fef4 100644 --- a/src/Native/libcryptonight/crypto/Asm.h +++ b/src/Native/libcryptonight/xmrig/extra.h @@ -5,7 +5,8 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,30 +22,20 @@ * along with this program. If not, see . */ -#ifndef XMRIG_ASM_H -#define XMRIG_ASM_H - - -#include "common/xmrig.h" -#include "rapidjson/fwd.h" +#pragma once +#include "crypto/CryptoNight.h" namespace xmrig { +class CpuThread { + public: + typedef void (*cn_mainloop_fun)(cryptonight_ctx *ctx); + typedef void (*cn_mainloop_double_fun)(cryptonight_ctx *ctx1, cryptonight_ctx *ctx2); -class Asm -{ -public: - static Assembly parse(const char *assembly, Assembly defaultValue = ASM_AUTO); - static Assembly parse(const rapidjson::Value &value, Assembly defaultValue = ASM_AUTO); - static const char *toString(Assembly assembly); - static rapidjson::Value toJSON(Assembly assembly); - - inline static Assembly parse(bool enable) { return enable ? ASM_AUTO : ASM_NONE; } +# ifndef XMRIG_NO_ASM + static void patchAsmVariants(); +# endif }; - -} /* namespace xmrig */ - - -#endif /* XMRIG_ASM_H */ +} diff --git a/src/Native/libcryptonote/Makefile b/src/Native/libcryptonote/Makefile index a30513767..2b1b84aad 100644 --- a/src/Native/libcryptonote/Makefile +++ b/src/Native/libcryptonote/Makefile @@ -11,7 +11,7 @@ OBJECTS = contrib/epee/src/hex.o \ contrib/epee/src/memwipe.o \ crypto/crypto-ops-data.o crypto/crypto-ops.o crypto/crypto.o crypto/groestl.o crypto/hash-extra-blake.o \ crypto/hash-extra-groestl.o crypto/hash-extra-jh.o crypto/hash-extra-skein.o crypto/hash.o crypto/jh.o \ - crypto/keccak.o crypto/oaes_lib.o crypto/random.o crypto/skein.o crypto/slow-hash.o crypto/tree-hash.o \ + crypto/keccak.o crypto/oaes_lib.o crypto/random.o crypto/skein.o crypto/tree-hash.o \ crypto/slow-hash-lite.o cryptonote_basic/cryptonote_format_utils.o exports.o all: $(TARGET) diff --git a/src/Native/libcryptonote/Makefile.MSys2 b/src/Native/libcryptonote/Makefile.MSys2 index a04d38435..87d3ee715 100644 --- a/src/Native/libcryptonote/Makefile.MSys2 +++ b/src/Native/libcryptonote/Makefile.MSys2 @@ -11,7 +11,7 @@ OBJECTS = contrib/epee/src/hex.o \ contrib/epee/src/memwipe.o \ crypto/crypto-ops-data.o crypto/crypto-ops.o crypto/crypto.o crypto/groestl.o crypto/hash-extra-blake.o \ crypto/hash-extra-groestl.o crypto/hash-extra-jh.o crypto/hash-extra-skein.o crypto/hash.o crypto/jh.o \ - crypto/keccak.o crypto/oaes_lib.o crypto/random.o crypto/skein.o crypto/slow-hash.o crypto/tree-hash.o \ + crypto/keccak.o crypto/oaes_lib.o crypto/random.o crypto/skein.o crypto/tree-hash.o \ crypto/slow-hash-lite.o cryptonote_basic/cryptonote_format_utils.o exports.o all: $(TARGET) diff --git a/src/Native/libcryptonote/exports.cpp b/src/Native/libcryptonote/exports.cpp index de8bdb66f..bf060e608 100644 --- a/src/Native/libcryptonote/exports.cpp +++ b/src/Native/libcryptonote/exports.cpp @@ -28,8 +28,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using namespace cryptonote; -extern "C" void cn_slow_hash_lite(const void *data, size_t length, char *hash); - #ifdef _WIN32 #define MODULE_API __declspec(dllexport) #else @@ -117,17 +115,7 @@ extern "C" MODULE_API uint64_t decode_integrated_address_export(const char* inpu return prefix; } -extern "C" MODULE_API void cn_slow_hash_export(const char* input, unsigned char *output, uint32_t inputSize, uint32_t variant) -{ - cn_slow_hash_old_sig((const void *) input, (const size_t) inputSize, (char *) output, variant); -} - extern "C" MODULE_API void cn_fast_hash_export(const char* input, unsigned char *output, uint32_t inputSize) { cn_fast_hash_old_sig((const void *)input, (const size_t) inputSize, (char *) output); } - -extern "C" MODULE_API void cn_slow_hash_lite_export(const char* input, unsigned char *output, uint32_t inputSize) -{ - cn_slow_hash_lite((const void *)input, (const size_t)inputSize, (char *)output); -} diff --git a/src/Native/libcryptonote/libcryptonote.vcxproj b/src/Native/libcryptonote/libcryptonote.vcxproj index 263a574b9..17d41aa6b 100644 --- a/src/Native/libcryptonote/libcryptonote.vcxproj +++ b/src/Native/libcryptonote/libcryptonote.vcxproj @@ -225,7 +225,6 @@ - diff --git a/src/Native/libcryptonote/libcryptonote.vcxproj.filters b/src/Native/libcryptonote/libcryptonote.vcxproj.filters index 228959932..20c4e7e41 100644 --- a/src/Native/libcryptonote/libcryptonote.vcxproj.filters +++ b/src/Native/libcryptonote/libcryptonote.vcxproj.filters @@ -163,9 +163,6 @@ Source Files - - Source Files - Source Files @@ -190,15 +187,15 @@ Source Files - - Source Files - Source Files Source Files + + Source Files + From 236bf5340a83a58d87ee8c3e31740fa1be5bff59 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 25 Feb 2019 16:03:19 +0100 Subject: [PATCH 099/178] Refactor --- .../Blockchain/Cryptonote/CryptonoteJob.cs | 28 ++++++++----------- src/Miningcore/Configuration/ClusterConfig.cs | 5 +++- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs index 24318c240..436136f43 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs @@ -166,35 +166,29 @@ public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out throw new StratumException(StratumError.MinusOne, "malformed blob"); // determine variant - CryptonightVariant variant; + CryptonightVariant variant = CryptonightVariant.VARIANT_0; if (coin.HashVariant != 0) - variant = (CryptonightVariant)coin.HashVariant; + variant = (CryptonightVariant) coin.HashVariant; else { - switch(blobConverted[0]) + switch (coin.Hash) { - case 13: - variant = CryptonightVariant.VARIANT_4; + case CryptonightHashType.Normal: + variant = (blobConverted[0] >= 10) ? CryptonightVariant.VARIANT_4 : + ((blobConverted[0] >= 8) ? CryptonightVariant.VARIANT_2 : + ((blobConverted[0] == 7) ? CryptonightVariant.VARIANT_1 : + CryptonightVariant.VARIANT_0)); break; - case 12: - variant = CryptonightVariant.VARIANT_WOW; - break; - - case 9: - case 8: - variant = CryptonightVariant.VARIANT_2; - break; - - case 7: + case CryptonightHashType.Lite: variant = CryptonightVariant.VARIANT_1; break; - default: + case CryptonightHashType.Heavy: variant = CryptonightVariant.VARIANT_0; break; - } + } } // hash it diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index 04b1c4802..944f5034a 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -241,7 +241,10 @@ public enum CryptonightHashType Lite, [EnumMember(Value = "cryptonight-heavy")] - Heavy + Heavy, + + [EnumMember(Value = "cryptonight-pico")] + Pico } public partial class CryptonoteCoinTemplate : CoinTemplate From ad60fff850dc7ffd1eebbaad708e06dabaac564c Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sat, 2 Mar 2019 13:44:14 +0100 Subject: [PATCH 100/178] Fix rate limit stuff --- src/Miningcore/Program.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Miningcore/Program.cs b/src/Miningcore/Program.cs index 463d3c03f..871ad4e1b 100644 --- a/src/Miningcore/Program.cs +++ b/src/Miningcore/Program.cs @@ -716,6 +716,7 @@ private static void StartApi() services.Configure(ConfigureIpRateLimitOptions); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); } // MVC @@ -726,7 +727,7 @@ private static void StartApi() services.AddSingleton(); services.AddMvc() - .SetCompatibilityVersion(CompatibilityVersion.Version_2_1) + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .AddControllersAsServices() .AddJsonOptions(options => { From 0f55c0376552f0c8c0f12c285b11dc1730aea3a3 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sat, 2 Mar 2019 13:52:58 +0100 Subject: [PATCH 101/178] Cleanup --- src/Miningcore/Program.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Miningcore/Program.cs b/src/Miningcore/Program.cs index 871ad4e1b..a59b456ab 100644 --- a/src/Miningcore/Program.cs +++ b/src/Miningcore/Program.cs @@ -719,13 +719,14 @@ private static void StartApi() services.AddSingleton(); } - // MVC - services.AddSingleton((IComponentContext) container); - services.AddSingleton(); - + // Controllers services.AddSingleton(); services.AddSingleton(); + // MVC + services.AddSingleton((IComponentContext)container); + services.AddSingleton(); + services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .AddControllersAsServices() From 81b343d676ae1e77fe842e5e60bc8f1857e15eb8 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sat, 2 Mar 2019 17:46:38 +0100 Subject: [PATCH 102/178] Readonly span --- src/Miningcore/Crypto/Hashing/Equihash/EquihashSolver.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Miningcore/Crypto/Hashing/Equihash/EquihashSolver.cs b/src/Miningcore/Crypto/Hashing/Equihash/EquihashSolver.cs index 5019b11c9..e3ad03299 100644 --- a/src/Miningcore/Crypto/Hashing/Equihash/EquihashSolver.cs +++ b/src/Miningcore/Crypto/Hashing/Equihash/EquihashSolver.cs @@ -55,7 +55,7 @@ public static int MaxThreads /// header including nonce (140 bytes) /// equihash solution without size-preamble /// - public abstract bool Verify(Span header, Span solution); + public abstract bool Verify(ReadOnlySpan header, ReadOnlySpan solution); } public unsafe class EquihashSolver_200_9 : EquihashSolver @@ -65,7 +65,7 @@ public EquihashSolver_200_9(string personalization) this.personalization = personalization; } - public override bool Verify(Span header, Span solution) + public override bool Verify(ReadOnlySpan header, ReadOnlySpan solution) { try { @@ -94,7 +94,7 @@ public EquihashSolver_144_5(string personalization) this.personalization = personalization; } - public override bool Verify(Span header, Span solution) + public override bool Verify(ReadOnlySpan header, ReadOnlySpan solution) { try { @@ -123,7 +123,7 @@ public EquihashSolver_96_5(string personalization) this.personalization = personalization; } - public override bool Verify(Span header, Span solution) + public override bool Verify(ReadOnlySpan header, ReadOnlySpan solution) { try { From 2dbad70879107d5a48f26048f1a82ef1cfe22def Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sat, 2 Mar 2019 17:54:59 +0100 Subject: [PATCH 103/178] Fixes #526 --- src/Miningcore/Notifications/NotificationService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Notifications/NotificationService.cs b/src/Miningcore/Notifications/NotificationService.cs index 1bbacb60c..2e0484590 100644 --- a/src/Miningcore/Notifications/NotificationService.cs +++ b/src/Miningcore/Notifications/NotificationService.cs @@ -59,7 +59,7 @@ public NotificationService( }); }); - messageBus.Listen() + messageBus.Listen() .Subscribe(x => { queue?.Add(new QueuedNotification From 58f33108e7c5c297af901e21923515c4a1712a88 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 8 Mar 2019 10:30:08 +0100 Subject: [PATCH 104/178] Sync Cryptonight with upstream --- libs/runtimes/win-x64/libcryptonight.dll | Bin 198144 -> 204800 bytes src/Miningcore/Native/LibCryptonight.cs | 3 + src/Native/libcryptonight/exports.cpp | 81 ++- .../libcryptonight/libcryptonight.vcxproj | 5 +- src/Native/libcryptonight/xmrig/Mem_win.cpp | 1 + .../libcryptonight/xmrig/common/xmrig.h | 33 +- .../libcryptonight/xmrig/crypto/CryptoNight.h | 4 + .../xmrig/crypto/CryptoNight_arm.h | 14 +- .../xmrig/crypto/CryptoNight_constants.h | 49 +- .../xmrig/crypto/CryptoNight_monero.h | 44 +- .../xmrig/crypto/CryptoNight_x86.h | 215 +++++-- .../xmrig/crypto/CryptonightR_gen.cpp | 29 +- .../asm/CryptonightR_soft_aes_template.inc | 279 +++++++++ .../CryptonightR_soft_aes_template_win.inc | 279 +++++++++ .../xmrig/crypto/asm/CryptonightR_template.S | 2 + .../xmrig/crypto/asm/CryptonightR_template.h | 24 + .../crypto/asm/CryptonightR_template.inc | 34 +- .../crypto/asm/CryptonightR_template_win.inc | 531 ++++++++++++++++++ .../asm/CryptonightWOW_soft_aes_template.inc | 266 +++++++++ .../CryptonightWOW_soft_aes_template_win.inc | 266 +++++++++ .../asm/CryptonightWOW_template_win.inc | 486 ++++++++++++++++ .../asm/cn2/cnv2_rwz_double_main_loop.inc | 410 ++++++++++++++ .../crypto/asm/cn2/cnv2_rwz_main_loop.inc | 186 ++++++ .../xmrig/crypto/asm/cn_main_loop.S | 20 + .../CryptonightR_soft_aes_template_win.inc | 279 +++++++++ .../asm/win64/CryptonightR_template.asm | 2 + .../asm/win64/CryptonightR_template_win.inc | 34 +- .../CryptonightWOW_soft_aes_template_win.inc | 266 +++++++++ .../win64/cn2/cnv2_rwz_double_main_loop.inc | 410 ++++++++++++++ .../asm/win64/cn2/cnv2_rwz_main_loop.inc | 186 ++++++ .../xmrig/crypto/asm/win64/cn_main_loop.S | 14 + .../xmrig/crypto/asm/win64/cn_main_loop.asm | 16 + .../xmrig/crypto/cn_gpu_arm.cpp | 8 + src/Native/libcryptonight/xmrig/extra.cpp | 48 +- 34 files changed, 4364 insertions(+), 160 deletions(-) create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_soft_aes_template.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_soft_aes_template_win.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template_win.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_soft_aes_template.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_soft_aes_template_win.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_template_win.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_rwz_double_main_loop.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_rwz_main_loop.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_soft_aes_template_win.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightWOW_soft_aes_template_win.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_rwz_double_main_loop.inc create mode 100644 src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_rwz_main_loop.inc diff --git a/libs/runtimes/win-x64/libcryptonight.dll b/libs/runtimes/win-x64/libcryptonight.dll index 4bdb9c811397312a38da9228bf9acde062f4047c..427ce9fcccba92a692a686dd32f7b6e090b20f1f 100644 GIT binary patch delta 49669 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�(;*uJOZz6pY@j$iwC~>M<;$Sjx&J)g! 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 TScSp2Q+%VXaPa)@zAyd>;>8=Q diff --git a/src/Miningcore/Native/LibCryptonight.cs b/src/Miningcore/Native/LibCryptonight.cs index c27451640..d190d033e 100644 --- a/src/Miningcore/Native/LibCryptonight.cs +++ b/src/Miningcore/Native/LibCryptonight.cs @@ -126,6 +126,9 @@ public enum CryptonightVariant VARIANT_GPU = 11, // CryptoNight-GPU (Ryo) VARIANT_WOW = 12, // CryptoNightR (Wownero) VARIANT_4 = 13, // CryptoNightR (Monero's variant 4) + VARIANT_RWZ = 14, // CryptoNight variant 2 with 3/4 iterations and reversed shuffle operation (Graft) + VARIANT_ZLS = 15, // CryptoNight variant 2 with 3/4 iterations (Zelerius) + VARIANT_DOUBLE = 16, // CryptoNight variant 2 with double iterations (X-CASH) VARIANT_MAX }; diff --git a/src/Native/libcryptonight/exports.cpp b/src/Native/libcryptonight/exports.cpp index d3704b5db..45146c564 100644 --- a/src/Native/libcryptonight/exports.cpp +++ b/src/Native/libcryptonight/exports.cpp @@ -31,7 +31,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #if (defined(__AES__) && (__AES__ == 1)) || (defined(__ARM_FEATURE_CRYPTO) && (__ARM_FEATURE_CRYPTO == 1)) #define SOFT_AES false #else -#warning Using software AES +// #warning Using software AES #define SOFT_AES true #endif @@ -41,6 +41,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define MODULE_API #endif +#define STRINGISE_IMPL(x) #x +#define STRINGISE(x) STRINGISE_IMPL(x) + extern "C" MODULE_API cryptonight_ctx *cryptonight_alloc_context_export() { cryptonight_ctx *ctx = NULL; Mem::create(&ctx, xmrig::CRYPTONIGHT, 1); @@ -77,34 +80,28 @@ extern "C" MODULE_API void cryptonight_free_ctx_export(cryptonight_ctx *ctx) { extern "C" MODULE_API void cryptonight_export(cryptonight_ctx* ctx, const char* input, unsigned char *output, size_t inputSize, uint32_t variant, uint64_t height) { switch (variant) { - case 0: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + case 0: cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); break; - case 1: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + case 1: cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); break; - case 3: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + case 3: cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); break; - case 4: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + case 4: cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); break; - case 6: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + case 6: cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); break; - case 7: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + case 7: cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); break; case 8: #if !SOFT_AES && defined(CPU_INTEL) - //#warning Using IvyBridge assembler implementation + // #warning Using IvyBridge assembler implementation cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); #elif !SOFT_AES && defined(CPU_AMD) - #warning Using Ryzen assembler implementation + // #warning Using Ryzen assembler implementation cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); #elif !SOFT_AES && defined(CPU_AMD_OLD) - #warning Using Bulldozer assembler implementation + // #warning Using Bulldozer assembler implementation cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); #else cryptonight_single_hash (reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); @@ -113,20 +110,19 @@ extern "C" MODULE_API void cryptonight_export(cryptonight_ctx* ctx, const char* case 9: #if !SOFT_AES && defined(CPU_INTEL) - //#warning Using IvyBridge assembler implementation + // #warning Using IvyBridge assembler implementation cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); #elif !SOFT_AES && defined(CPU_AMD) - #warning Using Ryzen assembler implementation + // #warning Using Ryzen assembler implementation cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); #elif !SOFT_AES && defined(CPU_AMD_OLD) - #warning Using Bulldozer assembler implementation + // #warning Using Bulldozer assembler implementation cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); #else cryptonight_single_hash (reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); #endif break; - case 11: - cryptonight_single_hash_gpu(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + case 11: cryptonight_single_hash_gpu(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); break; case 12: //if (!height_set) return THROW_ERROR_EXCEPTION("CryptonightR requires block template height as Argument 3"); @@ -141,21 +137,54 @@ extern "C" MODULE_API void cryptonight_export(cryptonight_ctx* ctx, const char* //if (!height_set) return THROW_ERROR_EXCEPTION("Cryptonight4 requires block template height as Argument 3"); #if !SOFT_AES && defined(CPU_INTEL) - //#warning Using IvyBridge assembler implementation + // #warning Using IvyBridge assembler implementation cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); #elif !SOFT_AES && defined(CPU_AMD) - #warning Using Ryzen assembler implementation + // #warning Using Ryzen assembler implementation cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); #elif !SOFT_AES && defined(CPU_AMD_OLD) - #warning Using Bulldozer assembler implementation + // #warning Using Bulldozer assembler implementation cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); #else cryptonight_single_hash (reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); #endif break; - default: - cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + case 14: + cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); + break; + + case 15: +#if !SOFT_AES && defined(CPU_INTEL) + // #warning Using IvyBridge assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#elif !SOFT_AES && defined(CPU_AMD) + // #warning Using Ryzen assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#elif !SOFT_AES && defined(CPU_AMD_OLD) + // #warning Using Bulldozer assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#else + cryptonight_single_hash (reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#endif + break; + + case 16: +#if !SOFT_AES && defined(CPU_INTEL) + // #warning Using IvyBridge assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#elif !SOFT_AES && defined(CPU_AMD) + // #warning Using Ryzen assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#elif !SOFT_AES && defined(CPU_AMD_OLD) + // #warning Using Bulldozer assembler implementation + cryptonight_single_hash_asm(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#else + cryptonight_single_hash (reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); +#endif + break; + + default: cryptonight_single_hash(reinterpret_cast(input), inputSize, reinterpret_cast(output), &ctx, height); } } diff --git a/src/Native/libcryptonight/libcryptonight.vcxproj b/src/Native/libcryptonight/libcryptonight.vcxproj index 2fa7b019a..520aa16cb 100644 --- a/src/Native/libcryptonight/libcryptonight.vcxproj +++ b/src/Native/libcryptonight/libcryptonight.vcxproj @@ -211,18 +211,15 @@ + - Document Document - - - diff --git a/src/Native/libcryptonight/xmrig/Mem_win.cpp b/src/Native/libcryptonight/xmrig/Mem_win.cpp index e6b4353a1..372ed5fa4 100644 --- a/src/Native/libcryptonight/xmrig/Mem_win.cpp +++ b/src/Native/libcryptonight/xmrig/Mem_win.cpp @@ -30,6 +30,7 @@ #include +//#include "common/log/Log.h" #include "common/utils/mm_malloc.h" #include "common/xmrig.h" #include "crypto/CryptoNight.h" diff --git a/src/Native/libcryptonight/xmrig/common/xmrig.h b/src/Native/libcryptonight/xmrig/common/xmrig.h index c6a5f5688..e8ca8857e 100644 --- a/src/Native/libcryptonight/xmrig/common/xmrig.h +++ b/src/Native/libcryptonight/xmrig/common/xmrig.h @@ -61,21 +61,24 @@ enum AlgoVariant { enum Variant { - VARIANT_AUTO = -1, // Autodetect - VARIANT_0 = 0, // Original CryptoNight or CryptoNight-Heavy - VARIANT_1 = 1, // CryptoNight variant 1 also known as Monero7 and CryptoNightV7 - VARIANT_TUBE = 2, // Modified CryptoNight-Heavy (TUBE only) - VARIANT_XTL = 3, // Modified CryptoNight variant 1 (Stellite only) - VARIANT_MSR = 4, // Modified CryptoNight variant 1 (Masari only) - VARIANT_XHV = 5, // Modified CryptoNight-Heavy (Haven Protocol only) - VARIANT_XAO = 6, // Modified CryptoNight variant 0 (Alloy only) - VARIANT_RTO = 7, // Modified CryptoNight variant 1 (Arto only) - VARIANT_2 = 8, // CryptoNight variant 2 - VARIANT_HALF = 9, // CryptoNight variant 2 with half iterations (Masari/Stellite) - VARIANT_TRTL = 10, // CryptoNight Turtle (TRTL) - VARIANT_GPU = 11, // CryptoNight-GPU (Ryo) - VARIANT_WOW = 12, // CryptoNightR (Wownero) - VARIANT_4 = 13, // CryptoNightR (Monero's variant 4) + VARIANT_AUTO = -1, // Autodetect + VARIANT_0 = 0, // Original CryptoNight or CryptoNight-Heavy + VARIANT_1 = 1, // CryptoNight variant 1 also known as Monero7 and CryptoNightV7 + VARIANT_TUBE = 2, // Modified CryptoNight-Heavy (TUBE only) + VARIANT_XTL = 3, // Modified CryptoNight variant 1 (Stellite only) + VARIANT_MSR = 4, // Modified CryptoNight variant 1 (Masari only) + VARIANT_XHV = 5, // Modified CryptoNight-Heavy (Haven Protocol only) + VARIANT_XAO = 6, // Modified CryptoNight variant 0 (Alloy only) + VARIANT_RTO = 7, // Modified CryptoNight variant 1 (Arto only) + VARIANT_2 = 8, // CryptoNight variant 2 + VARIANT_HALF = 9, // CryptoNight variant 2 with half iterations (Masari/Stellite) + VARIANT_TRTL = 10, // CryptoNight Turtle (TRTL) + VARIANT_GPU = 11, // CryptoNight-GPU (Ryo) + VARIANT_WOW = 12, // CryptoNightR (Wownero) + VARIANT_4 = 13, // CryptoNightR (Monero's variant 4) + VARIANT_RWZ = 14, // CryptoNight variant 2 with 3/4 iterations and reversed shuffle operation (Graft) + VARIANT_ZLS = 15, // CryptoNight variant 2 with 3/4 iterations (Zelerius) + VARIANT_DOUBLE = 16, // CryptoNight variant 2 with double iterations (X-CASH) VARIANT_MAX }; diff --git a/src/Native/libcryptonight/xmrig/crypto/CryptoNight.h b/src/Native/libcryptonight/xmrig/crypto/CryptoNight.h index b92945e4e..91a4c7b71 100644 --- a/src/Native/libcryptonight/xmrig/crypto/CryptoNight.h +++ b/src/Native/libcryptonight/xmrig/crypto/CryptoNight.h @@ -49,6 +49,10 @@ struct cryptonight_r_data { struct cryptonight_ctx { alignas(16) uint8_t state[224]; alignas(16) uint8_t *memory; + + uint8_t unused[40]; + const uint32_t* saes_table; + cn_mainloop_fun_ms_abi generated_code; cn_mainloop_double_fun_ms_abi generated_code_double; cryptonight_r_data generated_code_data; diff --git a/src/Native/libcryptonight/xmrig/crypto/CryptoNight_arm.h b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_arm.h index e7232eb1f..d762929c2 100644 --- a/src/Native/libcryptonight/xmrig/crypto/CryptoNight_arm.h +++ b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_arm.h @@ -436,7 +436,7 @@ static inline void cryptonight_monero_tweak(const uint8_t* l, uint64_t idx, __m1 uint64_t* mem_out = (uint64_t*)&l[idx]; if (BASE == xmrig::VARIANT_2) { - VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1, cx); + VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1, cx, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); _mm_store_si128((__m128i *)mem_out, _mm_xor_si128(bx0, cx)); } else { __m128i tmp = _mm_xor_si128(bx0, cx); @@ -530,9 +530,9 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si if (BASE == xmrig::VARIANT_2) { if (VARIANT == xmrig::VARIANT_4) { - VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx0, bx1, cx); + VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx0, bx1, cx, 0); } else { - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo); + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); } } @@ -709,9 +709,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si if (BASE == xmrig::VARIANT_2) { if (VARIANT == xmrig::VARIANT_4) { - VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx00, bx01, cx0); + VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx00, bx01, cx0, 0); } else { - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo); + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); } } @@ -767,9 +767,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si if (BASE == xmrig::VARIANT_2) { if (VARIANT == xmrig::VARIANT_4) { - VARIANT2_SHUFFLE(l1, idx1 & MASK, ax1, bx10, bx11, cx1); + VARIANT2_SHUFFLE(l1, idx1 & MASK, ax1, bx10, bx11, cx1, 0); } else { - VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo); + VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); } } diff --git a/src/Native/libcryptonight/xmrig/crypto/CryptoNight_constants.h b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_constants.h index 4ea1adb3b..b04ce08d4 100644 --- a/src/Native/libcryptonight/xmrig/crypto/CryptoNight_constants.h +++ b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_constants.h @@ -42,6 +42,9 @@ constexpr const uint32_t CRYPTONIGHT_MASK = 0x1FFFF0; constexpr const uint32_t CRYPTONIGHT_ITER = 0x80000; constexpr const uint32_t CRYPTONIGHT_HALF_ITER = 0x40000; constexpr const uint32_t CRYPTONIGHT_XAO_ITER = 0x100000; +constexpr const uint32_t CRYPTONIGHT_DOUBLE_ITER = 0x100000; +constexpr const uint32_t CRYPTONIGHT_WALTZ_ITER = 0x60000; +constexpr const uint32_t CRYPTONIGHT_ZLS_ITER = 0x60000; constexpr const uint32_t CRYPTONIGHT_GPU_ITER = 0xC000; constexpr const uint32_t CRYPTONIGHT_GPU_MASK = 0x1FFFC0; @@ -134,6 +137,9 @@ template<> inline constexpr uint32_t cn_select_iter() template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_XAO_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_GPU_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_WALTZ_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ZLS_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_DOUBLE_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } @@ -153,11 +159,16 @@ inline uint32_t cn_select_iter(Algo algorithm, Variant variant) return CRYPTONIGHT_GPU_ITER; case VARIANT_RTO: + case VARIANT_DOUBLE: return CRYPTONIGHT_XAO_ITER; case VARIANT_TRTL: return CRYPTONIGHT_TRTL_ITER; + case VARIANT_RWZ: + case VARIANT_ZLS: + return CRYPTONIGHT_WALTZ_ITER; + default: break; } @@ -184,26 +195,28 @@ inline uint32_t cn_select_iter(Algo algorithm, Variant variant) } -template inline constexpr Variant cn_base_variant() { return VARIANT_0; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_GPU; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } - +template inline constexpr Variant cn_base_variant() { return VARIANT_0; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_GPU; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } template inline constexpr bool cn_is_cryptonight_r() { return false; } -template<> inline constexpr bool cn_is_cryptonight_r() { return true; } -template<> inline constexpr bool cn_is_cryptonight_r() { return true; } +template<> inline constexpr bool cn_is_cryptonight_r() { return true; } +template<> inline constexpr bool cn_is_cryptonight_r() { return true; } } /* namespace xmrig */ diff --git a/src/Native/libcryptonight/xmrig/crypto/CryptoNight_monero.h b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_monero.h index 26c1fff0e..4e84ac5d0 100644 --- a/src/Native/libcryptonight/xmrig/crypto/CryptoNight_monero.h +++ b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_monero.h @@ -83,11 +83,11 @@ sqrt_result_xmm_##part = int_sqrt_v2(cx_0 + division_result); \ } while (0) -# define VARIANT2_SHUFFLE(base_ptr, offset, _a, _b, _b1, _c) \ +# define VARIANT2_SHUFFLE(base_ptr, offset, _a, _b, _b1, _c, reverse) \ do { \ - const __m128i chunk1 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10))); \ + const __m128i chunk1 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ (reverse ? 0x30 : 0x10)))); \ const __m128i chunk2 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20))); \ - const __m128i chunk3 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30))); \ + const __m128i chunk3 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ (reverse ? 0x10 : 0x30)))); \ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10)), _mm_add_epi64(chunk3, _b1)); \ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20)), _mm_add_epi64(chunk1, _b)); \ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30)), _mm_add_epi64(chunk2, _a)); \ @@ -96,15 +96,20 @@ } \ } while (0) -# define VARIANT2_SHUFFLE2(base_ptr, offset, _a, _b, _b1, hi, lo) \ +# define VARIANT2_SHUFFLE2(base_ptr, offset, _a, _b, _b1, hi, lo, reverse) \ do { \ const __m128i chunk1 = _mm_xor_si128(_mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10))), _mm_set_epi64x(lo, hi)); \ const __m128i chunk2 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20))); \ hi ^= ((uint64_t*)((base_ptr) + ((offset) ^ 0x20)))[0]; \ lo ^= ((uint64_t*)((base_ptr) + ((offset) ^ 0x20)))[1]; \ const __m128i chunk3 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30))); \ - _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10)), _mm_add_epi64(chunk3, _b1)); \ - _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20)), _mm_add_epi64(chunk1, _b)); \ + if (reverse) { \ + _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10)), _mm_add_epi64(chunk1, _b1)); \ + _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20)), _mm_add_epi64(chunk3, _b)); \ + } else { \ + _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10)), _mm_add_epi64(chunk3, _b1)); \ + _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20)), _mm_add_epi64(chunk1, _b)); \ + } \ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30)), _mm_add_epi64(chunk2, _a)); \ } while (0) @@ -128,11 +133,11 @@ sqrt_result_##part += ((r2 + b > sqrt_input) ? -1 : 0) + ((r2 + (1ULL << 32) < sqrt_input - s) ? 1 : 0); \ } while (0) -# define VARIANT2_SHUFFLE(base_ptr, offset, _a, _b, _b1, _c) \ +# define VARIANT2_SHUFFLE(base_ptr, offset, _a, _b, _b1, _c, reverse) \ do { \ - const uint64x2_t chunk1 = vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10))); \ + const uint64x2_t chunk1 = vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ (reverse ? 0x30 : 0x10)))); \ const uint64x2_t chunk2 = vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20))); \ - const uint64x2_t chunk3 = vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x30))); \ + const uint64x2_t chunk3 = vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ (reverse ? 0x10 : 0x30)))); \ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10)), vaddq_u64(chunk3, vreinterpretq_u64_u8(_b1))); \ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20)), vaddq_u64(chunk1, vreinterpretq_u64_u8(_b))); \ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x30)), vaddq_u64(chunk2, vreinterpretq_u64_u8(_a))); \ @@ -141,15 +146,20 @@ } \ } while (0) -# define VARIANT2_SHUFFLE2(base_ptr, offset, _a, _b, _b1, hi, lo) \ +# define VARIANT2_SHUFFLE2(base_ptr, offset, _a, _b, _b1, hi, lo, reverse) \ do { \ const uint64x2_t chunk1 = veorq_u64(vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10))), vcombine_u64(vcreate_u64(hi), vcreate_u64(lo))); \ const uint64x2_t chunk2 = vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20))); \ hi ^= ((uint64_t*)((base_ptr) + ((offset) ^ 0x20)))[0]; \ lo ^= ((uint64_t*)((base_ptr) + ((offset) ^ 0x20)))[1]; \ const uint64x2_t chunk3 = vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x30))); \ - vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10)), vaddq_u64(chunk3, vreinterpretq_u64_u8(_b1))); \ - vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20)), vaddq_u64(chunk1, vreinterpretq_u64_u8(_b))); \ + if (reverse) { \ + vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10)), vaddq_u64(chunk1, vreinterpretq_u64_u8(_b1))); \ + vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20)), vaddq_u64(chunk3, vreinterpretq_u64_u8(_b))); \ + } else { \ + vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10)), vaddq_u64(chunk3, vreinterpretq_u64_u8(_b1))); \ + vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20)), vaddq_u64(chunk1, vreinterpretq_u64_u8(_b))); \ + } \ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x30)), vaddq_u64(chunk2, vreinterpretq_u64_u8(_a))); \ } while (0) #endif @@ -158,6 +168,16 @@ #define SWAP64LE(x) x #define hash_extra_blake(data, length, hash) blake256_hash((uint8_t*)(hash), (uint8_t*)(data), (length)) +#ifndef NOINLINE +#ifdef __GNUC__ +#define NOINLINE __attribute__ ((noinline)) +#elif _MSC_VER +#define NOINLINE __declspec(noinline) +#else +#define NOINLINE +#endif +#endif + #include "common/xmrig.h" #include "variant4_random_math.h" diff --git a/src/Native/libcryptonight/xmrig/crypto/CryptoNight_x86.h b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_x86.h index 4c5d4ac04..8b9ea7836 100644 --- a/src/Native/libcryptonight/xmrig/crypto/CryptoNight_x86.h +++ b/src/Native/libcryptonight/xmrig/crypto/CryptoNight_x86.h @@ -192,31 +192,102 @@ static inline void aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, _ } +static FORCEINLINE void soft_aesenc(void* __restrict ptr, const void* __restrict key, const uint32_t* __restrict t) +{ + uint32_t x0 = ((const uint32_t*)(ptr))[0]; + uint32_t x1 = ((const uint32_t*)(ptr))[1]; + uint32_t x2 = ((const uint32_t*)(ptr))[2]; + uint32_t x3 = ((const uint32_t*)(ptr))[3]; + + uint32_t y0 = t[x0 & 0xff]; x0 >>= 8; + uint32_t y1 = t[x1 & 0xff]; x1 >>= 8; + uint32_t y2 = t[x2 & 0xff]; x2 >>= 8; + uint32_t y3 = t[x3 & 0xff]; x3 >>= 8; + t += 256; + + y0 ^= t[x1 & 0xff]; x1 >>= 8; + y1 ^= t[x2 & 0xff]; x2 >>= 8; + y2 ^= t[x3 & 0xff]; x3 >>= 8; + y3 ^= t[x0 & 0xff]; x0 >>= 8; + t += 256; + + y0 ^= t[x2 & 0xff]; x2 >>= 8; + y1 ^= t[x3 & 0xff]; x3 >>= 8; + y2 ^= t[x0 & 0xff]; x0 >>= 8; + y3 ^= t[x1 & 0xff]; x1 >>= 8; + t += 256; + + y0 ^= t[x3]; + y1 ^= t[x0]; + y2 ^= t[x1]; + y3 ^= t[x2]; + + ((uint32_t*)ptr)[0] = y0 ^ ((uint32_t*)key)[0]; + ((uint32_t*)ptr)[1] = y1 ^ ((uint32_t*)key)[1]; + ((uint32_t*)ptr)[2] = y2 ^ ((uint32_t*)key)[2]; + ((uint32_t*)ptr)[3] = y3 ^ ((uint32_t*)key)[3]; +} + +static FORCEINLINE __m128i soft_aesenc(const void* __restrict ptr, const __m128i key, const uint32_t* __restrict t) +{ + uint32_t x0 = ((const uint32_t*)(ptr))[0]; + uint32_t x1 = ((const uint32_t*)(ptr))[1]; + uint32_t x2 = ((const uint32_t*)(ptr))[2]; + uint32_t x3 = ((const uint32_t*)(ptr))[3]; + + uint32_t y0 = t[x0 & 0xff]; x0 >>= 8; + uint32_t y1 = t[x1 & 0xff]; x1 >>= 8; + uint32_t y2 = t[x2 & 0xff]; x2 >>= 8; + uint32_t y3 = t[x3 & 0xff]; x3 >>= 8; + t += 256; + + y0 ^= t[x1 & 0xff]; x1 >>= 8; + y1 ^= t[x2 & 0xff]; x2 >>= 8; + y2 ^= t[x3 & 0xff]; x3 >>= 8; + y3 ^= t[x0 & 0xff]; x0 >>= 8; + t += 256; + + y0 ^= t[x2 & 0xff]; x2 >>= 8; + y1 ^= t[x3 & 0xff]; x3 >>= 8; + y2 ^= t[x0 & 0xff]; x0 >>= 8; + y3 ^= t[x1 & 0xff]; x1 >>= 8; + + y0 ^= t[x3 + 256]; + y1 ^= t[x0 + 256]; + y2 ^= t[x1 + 256]; + y3 ^= t[x2 + 256]; + + return _mm_xor_si128(_mm_set_epi32(y3, y2, y1, y0), key); +} + template -static inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7) +void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7); + +template<> +NOINLINE void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7) { - if (SOFT_AES) { - *x0 = soft_aesenc((uint32_t*)x0, key); - *x1 = soft_aesenc((uint32_t*)x1, key); - *x2 = soft_aesenc((uint32_t*)x2, key); - *x3 = soft_aesenc((uint32_t*)x3, key); - *x4 = soft_aesenc((uint32_t*)x4, key); - *x5 = soft_aesenc((uint32_t*)x5, key); - *x6 = soft_aesenc((uint32_t*)x6, key); - *x7 = soft_aesenc((uint32_t*)x7, key); - } - else { - *x0 = _mm_aesenc_si128(*x0, key); - *x1 = _mm_aesenc_si128(*x1, key); - *x2 = _mm_aesenc_si128(*x2, key); - *x3 = _mm_aesenc_si128(*x3, key); - *x4 = _mm_aesenc_si128(*x4, key); - *x5 = _mm_aesenc_si128(*x5, key); - *x6 = _mm_aesenc_si128(*x6, key); - *x7 = _mm_aesenc_si128(*x7, key); - } + *x0 = soft_aesenc((uint32_t*)x0, key, (const uint32_t*)saes_table); + *x1 = soft_aesenc((uint32_t*)x1, key, (const uint32_t*)saes_table); + *x2 = soft_aesenc((uint32_t*)x2, key, (const uint32_t*)saes_table); + *x3 = soft_aesenc((uint32_t*)x3, key, (const uint32_t*)saes_table); + *x4 = soft_aesenc((uint32_t*)x4, key, (const uint32_t*)saes_table); + *x5 = soft_aesenc((uint32_t*)x5, key, (const uint32_t*)saes_table); + *x6 = soft_aesenc((uint32_t*)x6, key, (const uint32_t*)saes_table); + *x7 = soft_aesenc((uint32_t*)x7, key, (const uint32_t*)saes_table); } +template<> +FORCEINLINE void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7) +{ + *x0 = _mm_aesenc_si128(*x0, key); + *x1 = _mm_aesenc_si128(*x1, key); + *x2 = _mm_aesenc_si128(*x2, key); + *x3 = _mm_aesenc_si128(*x3, key); + *x4 = _mm_aesenc_si128(*x4, key); + *x5 = _mm_aesenc_si128(*x5, key); + *x6 = _mm_aesenc_si128(*x6, key); + *x7 = _mm_aesenc_si128(*x7, key); +} inline void mix_and_propagate(__m128i& x0, __m128i& x1, __m128i& x2, __m128i& x3, __m128i& x4, __m128i& x5, __m128i& x6, __m128i& x7) { @@ -460,7 +531,7 @@ template static inline void cryptonight_monero_tweak(uint64_t* mem_out, const uint8_t* l, uint64_t idx, __m128i ax0, __m128i bx0, __m128i bx1, __m128i& cx) { if (BASE == xmrig::VARIANT_2) { - VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1, cx); + VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1, cx, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); _mm_store_si128((__m128i *)mem_out, _mm_xor_si128(bx0, cx)); } else { __m128i tmp = _mm_xor_si128(bx0, cx); @@ -478,6 +549,8 @@ static inline void cryptonight_monero_tweak(uint64_t* mem_out, const uint8_t* l, } } +void wow_soft_aes_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); +void v4_soft_aes_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); template inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) @@ -498,9 +571,31 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si cn_explode_scratchpad((__m128i*) ctx[0]->state, (__m128i*) ctx[0]->memory); - const uint8_t* l0 = ctx[0]->memory; uint64_t* h0 = reinterpret_cast(ctx[0]->state); +#ifndef XMRIG_NO_ASM + if (SOFT_AES && xmrig::cn_is_cryptonight_r()) + { + if (!ctx[0]->generated_code_data.match(VARIANT, height)) { + V4_Instruction code[256]; + const int code_size = v4_random_math_init(code, height); + + if (VARIANT == xmrig::VARIANT_WOW) + wow_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), xmrig::ASM_NONE); + else if (VARIANT == xmrig::VARIANT_4) + v4_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), xmrig::ASM_NONE); + + ctx[0]->generated_code_data.variant = VARIANT; + ctx[0]->generated_code_data.height = height; + } + + ctx[0]->saes_table = (const uint32_t*)saes_table; + ctx[0]->generated_code(ctx[0]); + } else { +#endif + + const uint8_t* l0 = ctx[0]->memory; + VARIANT1_INIT(0); VARIANT2_INIT(0); VARIANT2_SET_ROUNDING_MODE(); @@ -524,7 +619,7 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si cx = aes_round_tweak_div(cx, ax0); } else if (SOFT_AES) { - cx = soft_aesenc((uint32_t*)&l0[idx0 & MASK], ax0); + cx = soft_aesenc((uint32_t*)&l0[idx0 & MASK], ax0, (const uint32_t*)saes_table); } else { cx = _mm_aesenc_si128(cx, ax0); @@ -558,9 +653,9 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si if (BASE == xmrig::VARIANT_2) { if (VARIANT == xmrig::VARIANT_4) { - VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx0, bx1, cx); + VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx0, bx1, cx, 0); } else { - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo); + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); } } @@ -602,6 +697,10 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si bx0 = cx; } +#ifndef XMRIG_NO_ASM + } +#endif + cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); xmrig::keccakf(h0, 24); @@ -655,6 +754,8 @@ extern "C" void cnv2_mainloop_ivybridge_asm(cryptonight_ctx *ctx); extern "C" void cnv2_mainloop_ryzen_asm(cryptonight_ctx *ctx); extern "C" void cnv2_mainloop_bulldozer_asm(cryptonight_ctx *ctx); extern "C" void cnv2_double_mainloop_sandybridge_asm(cryptonight_ctx* ctx0, cryptonight_ctx* ctx1); +extern "C" void cnv2_rwz_mainloop_asm(cryptonight_ctx *ctx); +extern "C" void cnv2_rwz_double_mainloop_asm(cryptonight_ctx* ctx0, cryptonight_ctx* ctx1); extern xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_ivybridge_asm; extern xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_ryzen_asm; @@ -666,6 +767,16 @@ extern xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_ryzen_asm; extern xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_bulldozer_asm; extern xmrig::CpuThread::cn_mainloop_double_fun cn_trtl_double_mainloop_sandybridge_asm; +extern xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_ivybridge_asm; +extern xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_ryzen_asm; +extern xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_bulldozer_asm; +extern xmrig::CpuThread::cn_mainloop_double_fun cn_zls_double_mainloop_sandybridge_asm; + +extern xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_ivybridge_asm; +extern xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_ryzen_asm; +extern xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_bulldozer_asm; +extern xmrig::CpuThread::cn_mainloop_double_fun cn_double_double_mainloop_sandybridge_asm; + void wow_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); void v4_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); void wow_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); @@ -744,6 +855,31 @@ inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_ cn_trtl_mainloop_bulldozer_asm(ctx[0]); } } + else if (VARIANT == xmrig::VARIANT_RWZ) { + cnv2_rwz_mainloop_asm(ctx[0]); + } + else if (VARIANT == xmrig::VARIANT_ZLS) { + if (ASM == xmrig::ASM_INTEL) { + cn_zls_mainloop_ivybridge_asm(ctx[0]); + } + else if (ASM == xmrig::ASM_RYZEN) { + cn_zls_mainloop_ryzen_asm(ctx[0]); + } + else { + cn_zls_mainloop_bulldozer_asm(ctx[0]); + } + } + else if (VARIANT == xmrig::VARIANT_DOUBLE) { + if (ASM == xmrig::ASM_INTEL) { + cn_double_mainloop_ivybridge_asm(ctx[0]); + } + else if (ASM == xmrig::ASM_RYZEN) { + cn_double_mainloop_ryzen_asm(ctx[0]); + } + else { + cn_double_mainloop_bulldozer_asm(ctx[0]); + } + } else if (xmrig::cn_is_cryptonight_r()) { ctx[0]->generated_code(ctx[0]); } @@ -782,6 +918,15 @@ inline void cryptonight_double_hash_asm(const uint8_t *__restrict__ input, size_ else if (VARIANT == xmrig::VARIANT_TRTL) { cn_trtl_double_mainloop_sandybridge_asm(ctx[0], ctx[1]); } + else if (VARIANT == xmrig::VARIANT_RWZ) { + cnv2_rwz_double_mainloop_asm(ctx[0], ctx[1]); + } + else if (VARIANT == xmrig::VARIANT_ZLS) { + cn_zls_double_mainloop_sandybridge_asm(ctx[0], ctx[1]); + } + else if (VARIANT == xmrig::VARIANT_DOUBLE) { + cn_double_double_mainloop_sandybridge_asm(ctx[0], ctx[1]); + } else if (xmrig::cn_is_cryptonight_r()) { ctx[0]->generated_code_double(ctx[0], ctx[1]); } @@ -857,8 +1002,8 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si cx1 = aes_round_tweak_div(cx1, ax1); } else if (SOFT_AES) { - cx0 = soft_aesenc((uint32_t*)&l0[idx0 & MASK], ax0); - cx1 = soft_aesenc((uint32_t*)&l1[idx1 & MASK], ax1); + cx0 = soft_aesenc((uint32_t*)&l0[idx0 & MASK], ax0, (const uint32_t*)saes_table); + cx1 = soft_aesenc((uint32_t*)&l1[idx1 & MASK], ax1, (const uint32_t*)saes_table); } else { cx0 = _mm_aesenc_si128(cx0, ax0); @@ -896,9 +1041,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si if (BASE == xmrig::VARIANT_2) { if (VARIANT == xmrig::VARIANT_4) { - VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx00, bx01, cx0); + VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx00, bx01, cx0, 0); } else { - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo); + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); } } @@ -952,9 +1097,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si if (BASE == xmrig::VARIANT_2) { if (VARIANT == xmrig::VARIANT_4) { - VARIANT2_SHUFFLE(l1, idx1 & MASK, ax1, bx10, bx11, cx1); + VARIANT2_SHUFFLE(l1, idx1 & MASK, ax1, bx10, bx11, cx1, 0); } else { - VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo); + VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); } } @@ -1019,7 +1164,7 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si c = aes_round_tweak_div(c, a); \ } \ else if (SOFT_AES) { \ - c = soft_aesenc(c, a); \ + c = soft_aesenc(&c, a, (const uint32_t*)saes_table); \ } else { \ c = _mm_aesenc_si128(c, a); \ } \ @@ -1056,9 +1201,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si lo = __umul128(idx, cl##part, &hi); \ if (BASE == xmrig::VARIANT_2) { \ if (VARIANT == xmrig::VARIANT_4) { \ - VARIANT2_SHUFFLE(l, idx & MASK, a, b0, b1, c); \ + VARIANT2_SHUFFLE(l, idx & MASK, a, b0, b1, c, 0); \ } else { \ - VARIANT2_SHUFFLE2(l, idx & MASK, a, b0, b1, hi, lo); \ + VARIANT2_SHUFFLE2(l, idx & MASK, a, b0, b1, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); \ } \ } \ if (VARIANT == xmrig::VARIANT_4) { \ diff --git a/src/Native/libcryptonight/xmrig/crypto/CryptonightR_gen.cpp b/src/Native/libcryptonight/xmrig/crypto/CryptonightR_gen.cpp index 55f94662c..3fba49cd9 100644 --- a/src/Native/libcryptonight/xmrig/crypto/CryptonightR_gen.cpp +++ b/src/Native/libcryptonight/xmrig/crypto/CryptonightR_gen.cpp @@ -31,7 +31,6 @@ typedef void(*void_func)(); #include "crypto/asm/CryptonightR_template.h" #include "Mem.h" -#if !defined XMRIG_ARM && !defined XMRIG_NO_ASM static inline void add_code(uint8_t* &p, void (*p1)(), void (*p2)()) { @@ -159,4 +158,30 @@ void v4_compile_code_double(const V4_Instruction* code, int code_size, void* mac Mem::flushInstructionCache(machine_code, p - p0); } -#endif +void wow_soft_aes_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) +{ + uint8_t* p0 = reinterpret_cast(machine_code); + uint8_t* p = p0; + + add_code(p, CryptonightWOW_soft_aes_template_part1, CryptonightWOW_soft_aes_template_part2); + add_random_math(p, code, code_size, instructions, instructions_mov, false, ASM); + add_code(p, CryptonightWOW_soft_aes_template_part2, CryptonightWOW_soft_aes_template_part3); + *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightWOW_soft_aes_template_mainloop) - ((const uint8_t*)CryptonightWOW_soft_aes_template_part1)) - (p - p0)); + add_code(p, CryptonightWOW_soft_aes_template_part3, CryptonightWOW_soft_aes_template_end); + + Mem::flushInstructionCache(machine_code, p - p0); +} + +void v4_soft_aes_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) +{ + uint8_t* p0 = reinterpret_cast(machine_code); + uint8_t* p = p0; + + add_code(p, CryptonightR_soft_aes_template_part1, CryptonightR_soft_aes_template_part2); + add_random_math(p, code, code_size, instructions, instructions_mov, false, ASM); + add_code(p, CryptonightR_soft_aes_template_part2, CryptonightR_soft_aes_template_part3); + *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightR_soft_aes_template_mainloop) - ((const uint8_t*)CryptonightR_soft_aes_template_part1)) - (p - p0)); + add_code(p, CryptonightR_soft_aes_template_part3, CryptonightR_soft_aes_template_end); + + Mem::flushInstructionCache(machine_code, p - p0); +} diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_soft_aes_template.inc b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_soft_aes_template.inc new file mode 100644 index 000000000..40c7874d2 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_soft_aes_template.inc @@ -0,0 +1,279 @@ +PUBLIC FN_PREFIX(CryptonightR_soft_aes_template_part1) +PUBLIC FN_PREFIX(CryptonightR_soft_aes_template_mainloop) +PUBLIC FN_PREFIX(CryptonightR_soft_aes_template_part2) +PUBLIC FN_PREFIX(CryptonightR_soft_aes_template_part3) +PUBLIC FN_PREFIX(CryptonightR_soft_aes_template_end) + +ALIGN(64) +FN_PREFIX(CryptonightR_soft_aes_template_part1): + mov QWORD PTR [rsp+8], rcx + push rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 232 + + mov eax, [rcx+96] + mov ebx, [rcx+100] + mov esi, [rcx+104] + mov edx, [rcx+108] + mov [rsp+144], eax + mov [rsp+148], ebx + mov [rsp+152], esi + mov [rsp+156], edx + + mov rax, QWORD PTR [rcx+48] + mov r10, rcx + xor rax, QWORD PTR [rcx+16] + mov r8, QWORD PTR [rcx+32] + xor r8, QWORD PTR [rcx] + mov r9, QWORD PTR [rcx+40] + xor r9, QWORD PTR [rcx+8] + movq xmm4, rax + mov rdx, QWORD PTR [rcx+56] + xor rdx, QWORD PTR [rcx+24] + mov r11, QWORD PTR [rcx+224] + mov rcx, QWORD PTR [rcx+88] + xor rcx, QWORD PTR [r10+72] + mov rax, QWORD PTR [r10+80] + movq xmm0, rdx + xor rax, QWORD PTR [r10+64] + + movaps XMMWORD PTR [rsp+16], xmm6 + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+48], xmm8 + movaps XMMWORD PTR [rsp+64], xmm9 + movaps XMMWORD PTR [rsp+80], xmm10 + movaps XMMWORD PTR [rsp+96], xmm11 + movaps XMMWORD PTR [rsp+112], xmm12 + movaps XMMWORD PTR [rsp+128], xmm13 + + movq xmm5, rax + + mov rax, r8 + punpcklqdq xmm4, xmm0 + and eax, 2097136 + movq xmm10, QWORD PTR [r10+96] + movq xmm0, rcx + mov rcx, QWORD PTR [r10+104] + xorps xmm9, xmm9 + mov QWORD PTR [rsp+328], rax + movq xmm12, r11 + mov QWORD PTR [rsp+320], r9 + punpcklqdq xmm5, xmm0 + movq xmm13, rcx + mov r12d, 524288 + + ALIGN(64) +FN_PREFIX(CryptonightR_soft_aes_template_mainloop): + movd xmm11, r12d + mov r12, QWORD PTR [r10+272] + lea r13, QWORD PTR [rax+r11] + mov esi, DWORD PTR [r13] + movq xmm0, r9 + mov r10d, DWORD PTR [r13+4] + movq xmm7, r8 + mov ebp, DWORD PTR [r13+12] + mov r14d, DWORD PTR [r13+8] + mov rdx, QWORD PTR [rsp+328] + movzx ecx, sil + shr esi, 8 + punpcklqdq xmm7, xmm0 + mov r15d, DWORD PTR [r12+rcx*4] + movzx ecx, r10b + shr r10d, 8 + mov edi, DWORD PTR [r12+rcx*4] + movzx ecx, r14b + shr r14d, 8 + mov ebx, DWORD PTR [r12+rcx*4] + movzx ecx, bpl + shr ebp, 8 + mov r9d, DWORD PTR [r12+rcx*4] + movzx ecx, r10b + shr r10d, 8 + xor r15d, DWORD PTR [r12+rcx*4+1024] + movzx ecx, r14b + shr r14d, 8 + mov eax, r14d + shr eax, 8 + xor edi, DWORD PTR [r12+rcx*4+1024] + add eax, 256 + movzx ecx, bpl + shr ebp, 8 + xor ebx, DWORD PTR [r12+rcx*4+1024] + movzx ecx, sil + shr esi, 8 + xor r9d, DWORD PTR [r12+rcx*4+1024] + add r12, 2048 + movzx ecx, r10b + shr r10d, 8 + add r10d, 256 + mov r11d, DWORD PTR [r12+rax*4] + xor r11d, DWORD PTR [r12+rcx*4] + xor r11d, r9d + movzx ecx, sil + mov r10d, DWORD PTR [r12+r10*4] + shr esi, 8 + add esi, 256 + xor r10d, DWORD PTR [r12+rcx*4] + movzx ecx, bpl + xor r10d, ebx + shr ebp, 8 + movd xmm1, r11d + add ebp, 256 + movq r11, xmm12 + mov r9d, DWORD PTR [r12+rcx*4] + xor r9d, DWORD PTR [r12+rsi*4] + mov eax, DWORD PTR [r12+rbp*4] + xor r9d, edi + movzx ecx, r14b + movd xmm0, r10d + movd xmm2, r9d + xor eax, DWORD PTR [r12+rcx*4] + mov rcx, rdx + xor eax, r15d + punpckldq xmm2, xmm1 + xor rcx, 16 + movd xmm6, eax + mov rax, rdx + punpckldq xmm6, xmm0 + xor rax, 32 + punpckldq xmm6, xmm2 + xor rdx, 48 + movdqu xmm2, XMMWORD PTR [rcx+r11] + pxor xmm6, xmm2 + pxor xmm6, xmm7 + paddq xmm2, xmm4 + movdqu xmm1, XMMWORD PTR [rax+r11] + movdqu xmm0, XMMWORD PTR [rdx+r11] + pxor xmm6, xmm1 + pxor xmm6, xmm0 + paddq xmm0, xmm5 + movdqu XMMWORD PTR [rcx+r11], xmm0 + movdqu XMMWORD PTR [rax+r11], xmm2 + movq rcx, xmm13 + paddq xmm1, xmm7 + movdqu XMMWORD PTR [rdx+r11], xmm1 + movq rdi, xmm6 + mov r10, rdi + and r10d, 2097136 + movdqa xmm0, xmm6 + pxor xmm0, xmm4 + movdqu XMMWORD PTR [r13], xmm0 + + mov ebx, [rsp+144] + mov ebp, [rsp+152] + add ebx, [rsp+148] + add ebp, [rsp+156] + shl rbp, 32 + or rbx, rbp + + xor rbx, QWORD PTR [r10+r11] + lea r14, QWORD PTR [r10+r11] + mov rbp, QWORD PTR [r14+8] + + mov [rsp+160], rbx + mov [rsp+168], rdi + mov [rsp+176], rbp + mov [rsp+184], r10 + mov r10, rsp + + mov ebx, [rsp+144] + mov esi, [rsp+148] + mov edi, [rsp+152] + mov ebp, [rsp+156] + + movd esp, xmm7 + movaps xmm0, xmm7 + psrldq xmm0, 8 + movd r15d, xmm0 + movd eax, xmm4 + movd edx, xmm5 + movaps xmm0, xmm5 + psrldq xmm0, 8 + movd r9d, xmm0 + +FN_PREFIX(CryptonightR_soft_aes_template_part2): + mov rsp, r10 + mov [rsp+144], ebx + mov [rsp+148], esi + mov [rsp+152], edi + mov [rsp+156], ebp + + mov edi, edi + shl rbp, 32 + or rbp, rdi + xor r8, rbp + + mov ebx, ebx + shl rsi, 32 + or rsi, rbx + xor QWORD PTR [rsp+320], rsi + + mov rbx, [rsp+160] + mov rdi, [rsp+168] + mov rbp, [rsp+176] + mov r10, [rsp+184] + + mov r9, r10 + xor r9, 16 + mov rcx, r10 + xor rcx, 32 + xor r10, 48 + mov rax, rbx + mul rdi + movdqu xmm2, XMMWORD PTR [r9+r11] + movdqu xmm1, XMMWORD PTR [rcx+r11] + pxor xmm6, xmm2 + pxor xmm6, xmm1 + paddq xmm1, xmm7 + add r8, rdx + movdqu xmm0, XMMWORD PTR [r10+r11] + pxor xmm6, xmm0 + paddq xmm0, xmm5 + paddq xmm2, xmm4 + movdqu XMMWORD PTR [r9+r11], xmm0 + movdqa xmm5, xmm4 + mov r9, QWORD PTR [rsp+320] + movdqa xmm4, xmm6 + add r9, rax + movdqu XMMWORD PTR [rcx+r11], xmm2 + movdqu XMMWORD PTR [r10+r11], xmm1 + mov r10, QWORD PTR [rsp+304] + movd r12d, xmm11 + mov QWORD PTR [r14], r8 + xor r8, rbx + mov rax, r8 + mov QWORD PTR [r14+8], r9 + and eax, 2097136 + xor r9, rbp + mov QWORD PTR [rsp+320], r9 + mov QWORD PTR [rsp+328], rax + sub r12d, 1 + jne FN_PREFIX(CryptonightR_soft_aes_template_mainloop) + +FN_PREFIX(CryptonightR_soft_aes_template_part3): + movaps xmm6, XMMWORD PTR [rsp+16] + movaps xmm7, XMMWORD PTR [rsp+32] + movaps xmm8, XMMWORD PTR [rsp+48] + movaps xmm9, XMMWORD PTR [rsp+64] + movaps xmm10, XMMWORD PTR [rsp+80] + movaps xmm11, XMMWORD PTR [rsp+96] + movaps xmm12, XMMWORD PTR [rsp+112] + movaps xmm13, XMMWORD PTR [rsp+128] + + add rsp, 232 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + pop rbx + ret +FN_PREFIX(CryptonightR_soft_aes_template_end): diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_soft_aes_template_win.inc b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_soft_aes_template_win.inc new file mode 100644 index 000000000..d771f69cf --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_soft_aes_template_win.inc @@ -0,0 +1,279 @@ +PUBLIC CryptonightR_soft_aes_template_part1 +PUBLIC CryptonightR_soft_aes_template_mainloop +PUBLIC CryptonightR_soft_aes_template_part2 +PUBLIC CryptonightR_soft_aes_template_part3 +PUBLIC CryptonightR_soft_aes_template_end + +ALIGN(64) +CryptonightR_soft_aes_template_part1: + mov QWORD PTR [rsp+8], rcx + push rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 232 + + mov eax, [rcx+96] + mov ebx, [rcx+100] + mov esi, [rcx+104] + mov edx, [rcx+108] + mov [rsp+144], eax + mov [rsp+148], ebx + mov [rsp+152], esi + mov [rsp+156], edx + + mov rax, QWORD PTR [rcx+48] + mov r10, rcx + xor rax, QWORD PTR [rcx+16] + mov r8, QWORD PTR [rcx+32] + xor r8, QWORD PTR [rcx] + mov r9, QWORD PTR [rcx+40] + xor r9, QWORD PTR [rcx+8] + movq xmm4, rax + mov rdx, QWORD PTR [rcx+56] + xor rdx, QWORD PTR [rcx+24] + mov r11, QWORD PTR [rcx+224] + mov rcx, QWORD PTR [rcx+88] + xor rcx, QWORD PTR [r10+72] + mov rax, QWORD PTR [r10+80] + movq xmm0, rdx + xor rax, QWORD PTR [r10+64] + + movaps XMMWORD PTR [rsp+16], xmm6 + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+48], xmm8 + movaps XMMWORD PTR [rsp+64], xmm9 + movaps XMMWORD PTR [rsp+80], xmm10 + movaps XMMWORD PTR [rsp+96], xmm11 + movaps XMMWORD PTR [rsp+112], xmm12 + movaps XMMWORD PTR [rsp+128], xmm13 + + movq xmm5, rax + + mov rax, r8 + punpcklqdq xmm4, xmm0 + and eax, 2097136 + movq xmm10, QWORD PTR [r10+96] + movq xmm0, rcx + mov rcx, QWORD PTR [r10+104] + xorps xmm9, xmm9 + mov QWORD PTR [rsp+328], rax + movq xmm12, r11 + mov QWORD PTR [rsp+320], r9 + punpcklqdq xmm5, xmm0 + movq xmm13, rcx + mov r12d, 524288 + + ALIGN(64) +CryptonightR_soft_aes_template_mainloop: + movd xmm11, r12d + mov r12, QWORD PTR [r10+272] + lea r13, QWORD PTR [rax+r11] + mov esi, DWORD PTR [r13] + movq xmm0, r9 + mov r10d, DWORD PTR [r13+4] + movq xmm7, r8 + mov ebp, DWORD PTR [r13+12] + mov r14d, DWORD PTR [r13+8] + mov rdx, QWORD PTR [rsp+328] + movzx ecx, sil + shr esi, 8 + punpcklqdq xmm7, xmm0 + mov r15d, DWORD PTR [r12+rcx*4] + movzx ecx, r10b + shr r10d, 8 + mov edi, DWORD PTR [r12+rcx*4] + movzx ecx, r14b + shr r14d, 8 + mov ebx, DWORD PTR [r12+rcx*4] + movzx ecx, bpl + shr ebp, 8 + mov r9d, DWORD PTR [r12+rcx*4] + movzx ecx, r10b + shr r10d, 8 + xor r15d, DWORD PTR [r12+rcx*4+1024] + movzx ecx, r14b + shr r14d, 8 + mov eax, r14d + shr eax, 8 + xor edi, DWORD PTR [r12+rcx*4+1024] + add eax, 256 + movzx ecx, bpl + shr ebp, 8 + xor ebx, DWORD PTR [r12+rcx*4+1024] + movzx ecx, sil + shr esi, 8 + xor r9d, DWORD PTR [r12+rcx*4+1024] + add r12, 2048 + movzx ecx, r10b + shr r10d, 8 + add r10d, 256 + mov r11d, DWORD PTR [r12+rax*4] + xor r11d, DWORD PTR [r12+rcx*4] + xor r11d, r9d + movzx ecx, sil + mov r10d, DWORD PTR [r12+r10*4] + shr esi, 8 + add esi, 256 + xor r10d, DWORD PTR [r12+rcx*4] + movzx ecx, bpl + xor r10d, ebx + shr ebp, 8 + movd xmm1, r11d + add ebp, 256 + movq r11, xmm12 + mov r9d, DWORD PTR [r12+rcx*4] + xor r9d, DWORD PTR [r12+rsi*4] + mov eax, DWORD PTR [r12+rbp*4] + xor r9d, edi + movzx ecx, r14b + movd xmm0, r10d + movd xmm2, r9d + xor eax, DWORD PTR [r12+rcx*4] + mov rcx, rdx + xor eax, r15d + punpckldq xmm2, xmm1 + xor rcx, 16 + movd xmm6, eax + mov rax, rdx + punpckldq xmm6, xmm0 + xor rax, 32 + punpckldq xmm6, xmm2 + xor rdx, 48 + movdqu xmm2, XMMWORD PTR [rcx+r11] + pxor xmm6, xmm2 + pxor xmm6, xmm7 + paddq xmm2, xmm4 + movdqu xmm1, XMMWORD PTR [rax+r11] + movdqu xmm0, XMMWORD PTR [rdx+r11] + pxor xmm6, xmm1 + pxor xmm6, xmm0 + paddq xmm0, xmm5 + movdqu XMMWORD PTR [rcx+r11], xmm0 + movdqu XMMWORD PTR [rax+r11], xmm2 + movq rcx, xmm13 + paddq xmm1, xmm7 + movdqu XMMWORD PTR [rdx+r11], xmm1 + movq rdi, xmm6 + mov r10, rdi + and r10d, 2097136 + movdqa xmm0, xmm6 + pxor xmm0, xmm4 + movdqu XMMWORD PTR [r13], xmm0 + + mov ebx, [rsp+144] + mov ebp, [rsp+152] + add ebx, [rsp+148] + add ebp, [rsp+156] + shl rbp, 32 + or rbx, rbp + + xor rbx, QWORD PTR [r10+r11] + lea r14, QWORD PTR [r10+r11] + mov rbp, QWORD PTR [r14+8] + + mov [rsp+160], rbx + mov [rsp+168], rdi + mov [rsp+176], rbp + mov [rsp+184], r10 + mov r10, rsp + + mov ebx, [rsp+144] + mov esi, [rsp+148] + mov edi, [rsp+152] + mov ebp, [rsp+156] + + movd esp, xmm7 + movaps xmm0, xmm7 + psrldq xmm0, 8 + movd r15d, xmm0 + movd eax, xmm4 + movd edx, xmm5 + movaps xmm0, xmm5 + psrldq xmm0, 8 + movd r9d, xmm0 + +CryptonightR_soft_aes_template_part2: + mov rsp, r10 + mov [rsp+144], ebx + mov [rsp+148], esi + mov [rsp+152], edi + mov [rsp+156], ebp + + mov edi, edi + shl rbp, 32 + or rbp, rdi + xor r8, rbp + + mov ebx, ebx + shl rsi, 32 + or rsi, rbx + xor QWORD PTR [rsp+320], rsi + + mov rbx, [rsp+160] + mov rdi, [rsp+168] + mov rbp, [rsp+176] + mov r10, [rsp+184] + + mov r9, r10 + xor r9, 16 + mov rcx, r10 + xor rcx, 32 + xor r10, 48 + mov rax, rbx + mul rdi + movdqu xmm2, XMMWORD PTR [r9+r11] + movdqu xmm1, XMMWORD PTR [rcx+r11] + pxor xmm6, xmm2 + pxor xmm6, xmm1 + paddq xmm1, xmm7 + add r8, rdx + movdqu xmm0, XMMWORD PTR [r10+r11] + pxor xmm6, xmm0 + paddq xmm0, xmm5 + paddq xmm2, xmm4 + movdqu XMMWORD PTR [r9+r11], xmm0 + movdqa xmm5, xmm4 + mov r9, QWORD PTR [rsp+320] + movdqa xmm4, xmm6 + add r9, rax + movdqu XMMWORD PTR [rcx+r11], xmm2 + movdqu XMMWORD PTR [r10+r11], xmm1 + mov r10, QWORD PTR [rsp+304] + movd r12d, xmm11 + mov QWORD PTR [r14], r8 + xor r8, rbx + mov rax, r8 + mov QWORD PTR [r14+8], r9 + and eax, 2097136 + xor r9, rbp + mov QWORD PTR [rsp+320], r9 + mov QWORD PTR [rsp+328], rax + sub r12d, 1 + jne CryptonightR_soft_aes_template_mainloop + +CryptonightR_soft_aes_template_part3: + movaps xmm6, XMMWORD PTR [rsp+16] + movaps xmm7, XMMWORD PTR [rsp+32] + movaps xmm8, XMMWORD PTR [rsp+48] + movaps xmm9, XMMWORD PTR [rsp+64] + movaps xmm10, XMMWORD PTR [rsp+80] + movaps xmm11, XMMWORD PTR [rsp+96] + movaps xmm12, XMMWORD PTR [rsp+112] + movaps xmm13, XMMWORD PTR [rsp+128] + + add rsp, 232 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + pop rbx + ret +CryptonightR_soft_aes_template_end: diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.S b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.S index 5f3046cb9..d2974d160 100644 --- a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.S +++ b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.S @@ -531,6 +531,8 @@ PUBLIC FN_PREFIX(CryptonightR_instruction_mov256) #include "CryptonightWOW_template.inc" #include "CryptonightR_template.inc" +#include "CryptonightWOW_soft_aes_template.inc" +#include "CryptonightR_soft_aes_template.inc" FN_PREFIX(CryptonightR_instruction0): imul rbx, rbx diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.h b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.h index c2054705b..d9159a8f2 100644 --- a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.h +++ b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.h @@ -26,6 +26,30 @@ extern "C" void CryptonightR_template_double_part4(); void CryptonightR_template_double_end(); + void CryptonightWOW_soft_aes_template_part1(); + void CryptonightWOW_soft_aes_template_mainloop(); + void CryptonightWOW_soft_aes_template_part2(); + void CryptonightWOW_soft_aes_template_part3(); + void CryptonightWOW_soft_aes_template_end(); + void CryptonightWOW_soft_aes_template_double_part1(); + void CryptonightWOW_soft_aes_template_double_mainloop(); + void CryptonightWOW_soft_aes_template_double_part2(); + void CryptonightWOW_soft_aes_template_double_part3(); + void CryptonightWOW_soft_aes_template_double_part4(); + void CryptonightWOW_soft_aes_template_double_end(); + + void CryptonightR_soft_aes_template_part1(); + void CryptonightR_soft_aes_template_mainloop(); + void CryptonightR_soft_aes_template_part2(); + void CryptonightR_soft_aes_template_part3(); + void CryptonightR_soft_aes_template_end(); + void CryptonightR_soft_aes_template_double_part1(); + void CryptonightR_soft_aes_template_double_mainloop(); + void CryptonightR_soft_aes_template_double_part2(); + void CryptonightR_soft_aes_template_double_part3(); + void CryptonightR_soft_aes_template_double_part4(); + void CryptonightR_soft_aes_template_double_end(); + void CryptonightR_instruction0(); void CryptonightR_instruction1(); void CryptonightR_instruction2(); diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.inc b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.inc index b54486a57..8ecab7247 100644 --- a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.inc +++ b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template.inc @@ -70,29 +70,30 @@ FN_PREFIX(CryptonightR_template_mainloop): aesenc xmm5, xmm4 - mov r12d, r9d + mov r13d, r9d mov eax, r9d xor r9d, 48 - xor r12d, 16 + xor r13d, 16 xor eax, 32 movdqu xmm0, XMMWORD PTR [r9+r11] movaps xmm3, xmm0 - movdqu xmm2, XMMWORD PTR [r12+r11] + movdqu xmm2, XMMWORD PTR [r13+r11] movdqu xmm1, XMMWORD PTR [rax+r11] pxor xmm0, xmm2 pxor xmm5, xmm1 pxor xmm5, xmm0 + + movq r12, xmm5 + movd r10d, xmm5 + and r10d, 2097136 + paddq xmm3, xmm7 paddq xmm2, xmm6 paddq xmm1, xmm4 - movdqu XMMWORD PTR [r12+r11], xmm3 + movdqu XMMWORD PTR [r13+r11], xmm3 movdqu XMMWORD PTR [rax+r11], xmm2 movdqu XMMWORD PTR [r9+r11], xmm1 - movq r12, xmm5 - movd r10d, xmm5 - and r10d, 2097136 - movdqa xmm0, xmm5 pxor xmm0, xmm6 movdqu XMMWORD PTR [rdx], xmm0 @@ -102,14 +103,16 @@ FN_PREFIX(CryptonightR_template_mainloop): shl rdx, 32 or r13, rdx - xor r13, QWORD PTR [r10+r11] - mov r14, QWORD PTR [r10+r11+8] - movd eax, xmm6 movd edx, xmm7 pextrd r9d, xmm7, 2 + xor r13, QWORD PTR [r10+r11] + mov r14, QWORD PTR [r10+r11+8] + FN_PREFIX(CryptonightR_template_part2): + lea rcx, [r10+r11] + mov eax, edi mov edx, ebp shl rdx, 32 @@ -124,6 +127,8 @@ FN_PREFIX(CryptonightR_template_part2): mov rax, r13 mul r12 + add r15, rax + add rsp, rdx mov r9d, r10d mov r12d, r10d @@ -145,13 +150,10 @@ FN_PREFIX(CryptonightR_template_part2): movdqu XMMWORD PTR [r10+r11], xmm3 movdqa xmm7, xmm6 - add r15, rax - add rsp, rdx - xor r10, 48 - mov QWORD PTR [r10+r11], rsp + mov QWORD PTR [rcx], rsp xor rsp, r13 mov r9d, esp - mov QWORD PTR [r10+r11+8], r15 + mov QWORD PTR [rcx+8], r15 and r9d, 2097136 xor r15, r14 movdqa xmm6, xmm5 diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template_win.inc b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template_win.inc new file mode 100644 index 000000000..a170f2d2b --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightR_template_win.inc @@ -0,0 +1,531 @@ +PUBLIC CryptonightR_template_part1 +PUBLIC CryptonightR_template_mainloop +PUBLIC CryptonightR_template_part2 +PUBLIC CryptonightR_template_part3 +PUBLIC CryptonightR_template_end +PUBLIC CryptonightR_template_double_part1 +PUBLIC CryptonightR_template_double_mainloop +PUBLIC CryptonightR_template_double_part2 +PUBLIC CryptonightR_template_double_part3 +PUBLIC CryptonightR_template_double_part4 +PUBLIC CryptonightR_template_double_end + +ALIGN(64) +CryptonightR_template_part1: + mov QWORD PTR [rsp+16], rbx + mov QWORD PTR [rsp+24], rbp + mov QWORD PTR [rsp+32], rsi + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + push rdi + sub rsp, 64 + mov r12, rcx + mov r8, QWORD PTR [r12+32] + mov rdx, r12 + xor r8, QWORD PTR [r12] + mov r15, QWORD PTR [r12+40] + mov r9, r8 + xor r15, QWORD PTR [r12+8] + mov r11, QWORD PTR [r12+224] + mov r12, QWORD PTR [r12+56] + xor r12, QWORD PTR [rdx+24] + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + movaps XMMWORD PTR [rsp+48], xmm6 + movq xmm0, r12 + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+16], xmm8 + movaps XMMWORD PTR [rsp], xmm9 + mov r12, QWORD PTR [rdx+88] + xor r12, QWORD PTR [rdx+72] + movq xmm6, rax + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm6, xmm0 + and r9d, 2097136 + movq xmm0, r12 + movq xmm7, rax + punpcklqdq xmm7, xmm0 + mov r10d, r9d + movq xmm9, rsp + mov rsp, r8 + mov r8d, 524288 + + mov ebx, [rdx+96] + mov esi, [rdx+100] + mov edi, [rdx+104] + mov ebp, [rdx+108] + + ALIGN(64) +CryptonightR_template_mainloop: + movdqa xmm5, XMMWORD PTR [r9+r11] + movq xmm0, r15 + movq xmm4, rsp + punpcklqdq xmm4, xmm0 + lea rdx, QWORD PTR [r9+r11] + + aesenc xmm5, xmm4 + + mov r13d, r9d + mov eax, r9d + xor r9d, 48 + xor r13d, 16 + xor eax, 32 + movdqu xmm0, XMMWORD PTR [r9+r11] + movaps xmm3, xmm0 + movdqu xmm2, XMMWORD PTR [r13+r11] + movdqu xmm1, XMMWORD PTR [rax+r11] + pxor xmm0, xmm2 + pxor xmm5, xmm1 + pxor xmm5, xmm0 + + movq r12, xmm5 + movd r10d, xmm5 + and r10d, 2097136 + + paddq xmm3, xmm7 + paddq xmm2, xmm6 + paddq xmm1, xmm4 + movdqu XMMWORD PTR [r13+r11], xmm3 + movdqu XMMWORD PTR [rax+r11], xmm2 + movdqu XMMWORD PTR [r9+r11], xmm1 + + movdqa xmm0, xmm5 + pxor xmm0, xmm6 + movdqu XMMWORD PTR [rdx], xmm0 + + lea r13d, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or r13, rdx + + movd eax, xmm6 + movd edx, xmm7 + pextrd r9d, xmm7, 2 + + xor r13, QWORD PTR [r10+r11] + mov r14, QWORD PTR [r10+r11+8] + +CryptonightR_template_part2: + lea rcx, [r10+r11] + + mov eax, edi + mov edx, ebp + shl rdx, 32 + or rax, rdx + xor rsp, rax + + mov eax, ebx + mov edx, esi + shl rdx, 32 + or rax, rdx + xor r15, rax + + mov rax, r13 + mul r12 + add r15, rax + add rsp, rdx + + mov r9d, r10d + mov r12d, r10d + xor r9d, 16 + xor r12d, 32 + xor r10d, 48 + movdqa xmm1, XMMWORD PTR [r12+r11] + movaps xmm3, xmm1 + movdqa xmm2, XMMWORD PTR [r9+r11] + movdqa xmm0, XMMWORD PTR [r10+r11] + pxor xmm1, xmm2 + pxor xmm5, xmm0 + pxor xmm5, xmm1 + paddq xmm3, xmm4 + paddq xmm2, xmm6 + paddq xmm0, xmm7 + movdqu XMMWORD PTR [r9+r11], xmm0 + movdqu XMMWORD PTR [r12+r11], xmm2 + movdqu XMMWORD PTR [r10+r11], xmm3 + + movdqa xmm7, xmm6 + mov QWORD PTR [rcx], rsp + xor rsp, r13 + mov r9d, esp + mov QWORD PTR [rcx+8], r15 + and r9d, 2097136 + xor r15, r14 + movdqa xmm6, xmm5 + dec r8d + jnz CryptonightR_template_mainloop + +CryptonightR_template_part3: + movq rsp, xmm9 + + mov rbx, QWORD PTR [rsp+136] + mov rbp, QWORD PTR [rsp+144] + mov rsi, QWORD PTR [rsp+152] + movaps xmm6, XMMWORD PTR [rsp+48] + movaps xmm7, XMMWORD PTR [rsp+32] + movaps xmm8, XMMWORD PTR [rsp+16] + movaps xmm9, XMMWORD PTR [rsp] + add rsp, 64 + pop rdi + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + ret 0 +CryptonightR_template_end: + +ALIGN(64) +CryptonightR_template_double_part1: + mov QWORD PTR [rsp+24], rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 320 + mov r14, QWORD PTR [rcx+32] + mov r8, rcx + xor r14, QWORD PTR [rcx] + mov r12, QWORD PTR [rcx+40] + mov ebx, r14d + mov rsi, QWORD PTR [rcx+224] + and ebx, 2097136 + xor r12, QWORD PTR [rcx+8] + mov rcx, QWORD PTR [rcx+56] + xor rcx, QWORD PTR [r8+24] + mov rax, QWORD PTR [r8+48] + xor rax, QWORD PTR [r8+16] + mov r15, QWORD PTR [rdx+32] + xor r15, QWORD PTR [rdx] + movq xmm0, rcx + mov rcx, QWORD PTR [r8+88] + xor rcx, QWORD PTR [r8+72] + mov r13, QWORD PTR [rdx+40] + mov rdi, QWORD PTR [rdx+224] + xor r13, QWORD PTR [rdx+8] + movaps XMMWORD PTR [rsp+160], xmm6 + movaps XMMWORD PTR [rsp+176], xmm7 + movaps XMMWORD PTR [rsp+192], xmm8 + movaps XMMWORD PTR [rsp+208], xmm9 + movaps XMMWORD PTR [rsp+224], xmm10 + movaps XMMWORD PTR [rsp+240], xmm11 + movaps XMMWORD PTR [rsp+256], xmm12 + movaps XMMWORD PTR [rsp+272], xmm13 + movaps XMMWORD PTR [rsp+288], xmm14 + movaps XMMWORD PTR [rsp+304], xmm15 + movq xmm7, rax + mov rax, QWORD PTR [r8+80] + xor rax, QWORD PTR [r8+64] + + movaps xmm1, XMMWORD PTR [rdx+96] + movaps xmm2, XMMWORD PTR [r8+96] + movaps XMMWORD PTR [rsp], xmm1 + movaps XMMWORD PTR [rsp+16], xmm2 + + mov r8d, r15d + punpcklqdq xmm7, xmm0 + movq xmm0, rcx + mov rcx, QWORD PTR [rdx+56] + xor rcx, QWORD PTR [rdx+24] + movq xmm9, rax + mov QWORD PTR [rsp+128], rsi + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + punpcklqdq xmm9, xmm0 + movq xmm0, rcx + mov rcx, QWORD PTR [rdx+88] + xor rcx, QWORD PTR [rdx+72] + movq xmm8, rax + mov QWORD PTR [rsp+136], rdi + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm8, xmm0 + and r8d, 2097136 + movq xmm0, rcx + mov r11d, 524288 + movq xmm10, rax + punpcklqdq xmm10, xmm0 + + movq xmm14, QWORD PTR [rsp+128] + movq xmm15, QWORD PTR [rsp+136] + + ALIGN(64) +CryptonightR_template_double_mainloop: + movdqu xmm6, XMMWORD PTR [rbx+rsi] + movq xmm0, r12 + mov ecx, ebx + movq xmm3, r14 + punpcklqdq xmm3, xmm0 + xor ebx, 16 + aesenc xmm6, xmm3 + movq xmm4, r15 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + pxor xmm6, xmm0 + xor ebx, 48 + paddq xmm0, xmm7 + movdqu xmm1, XMMWORD PTR [rbx+rsi] + pxor xmm6, xmm1 + movdqu XMMWORD PTR [rbx+rsi], xmm0 + paddq xmm1, xmm3 + xor ebx, 16 + mov eax, ebx + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + pxor xmm6, xmm0 + movq rdx, xmm6 + movdqu XMMWORD PTR [rbx+rsi], xmm1 + paddq xmm0, xmm9 + movdqu XMMWORD PTR [rax+rsi], xmm0 + movdqa xmm0, xmm6 + pxor xmm0, xmm7 + movdqu XMMWORD PTR [rcx+rsi], xmm0 + mov esi, edx + movdqu xmm5, XMMWORD PTR [r8+rdi] + and esi, 2097136 + mov ecx, r8d + movq xmm0, r13 + punpcklqdq xmm4, xmm0 + xor r8d, 16 + aesenc xmm5, xmm4 + movdqu xmm0, XMMWORD PTR [r8+rdi] + pxor xmm5, xmm0 + xor r8d, 48 + paddq xmm0, xmm8 + movdqu xmm1, XMMWORD PTR [r8+rdi] + pxor xmm5, xmm1 + movdqu XMMWORD PTR [r8+rdi], xmm0 + paddq xmm1, xmm4 + xor r8d, 16 + mov eax, r8d + xor rax, 32 + movdqu xmm0, XMMWORD PTR [r8+rdi] + pxor xmm5, xmm0 + movdqu XMMWORD PTR [r8+rdi], xmm1 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rdi], xmm0 + movdqa xmm0, xmm5 + pxor xmm0, xmm8 + movdqu XMMWORD PTR [rcx+rdi], xmm0 + movq rdi, xmm5 + movq rcx, xmm14 + mov ebp, edi + mov r8, QWORD PTR [rcx+rsi] + mov r10, QWORD PTR [rcx+rsi+8] + lea r9, QWORD PTR [rcx+rsi] + xor esi, 16 + + movq xmm0, rsp + movq xmm1, rsi + movq xmm2, rdi + movq xmm11, rbp + movq xmm12, r15 + movq xmm13, rdx + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp+16] + mov esi, DWORD PTR [rsp+20] + mov edi, DWORD PTR [rsp+24] + mov ebp, DWORD PTR [rsp+28] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + xor r8, rax + + movd esp, xmm3 + pextrd r15d, xmm3, 2 + movd eax, xmm7 + movd edx, xmm9 + pextrd r9d, xmm9, 2 + +CryptonightR_template_double_part2: + + mov eax, edi + mov edx, ebp + shl rdx, 32 + or rax, rdx + xor r14, rax + + mov eax, ebx + mov edx, esi + shl rdx, 32 + or rax, rdx + xor r12, rax + + movq rsp, xmm0 + mov DWORD PTR [rsp+16], ebx + mov DWORD PTR [rsp+20], esi + mov DWORD PTR [rsp+24], edi + mov DWORD PTR [rsp+28], ebp + + movq rsi, xmm1 + movq rdi, xmm2 + movq rbp, xmm11 + movq r15, xmm12 + movq rdx, xmm13 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rbx, r8 + mov rax, r8 + mul rdx + and ebp, 2097136 + mov r8, rax + movdqu xmm1, XMMWORD PTR [rcx+rsi] + pxor xmm6, xmm1 + xor esi, 48 + paddq xmm1, xmm7 + movdqu xmm2, XMMWORD PTR [rsi+rcx] + pxor xmm6, xmm2 + paddq xmm2, xmm3 + movdqu XMMWORD PTR [rsi+rcx], xmm1 + xor esi, 16 + mov eax, esi + mov rsi, rcx + movdqu xmm0, XMMWORD PTR [rax+rcx] + pxor xmm6, xmm0 + movdqu XMMWORD PTR [rax+rcx], xmm2 + paddq xmm0, xmm9 + add r12, r8 + xor rax, 32 + add r14, rdx + movdqa xmm9, xmm7 + movdqa xmm7, xmm6 + movdqu XMMWORD PTR [rax+rcx], xmm0 + mov QWORD PTR [r9+8], r12 + xor r12, r10 + mov QWORD PTR [r9], r14 + movq rcx, xmm15 + xor r14, rbx + mov r10d, ebp + mov ebx, r14d + xor ebp, 16 + and ebx, 2097136 + mov r8, QWORD PTR [r10+rcx] + mov r9, QWORD PTR [r10+rcx+8] + + movq xmm0, rsp + movq xmm1, rbx + movq xmm2, rsi + movq xmm11, rdi + movq xmm12, rbp + movq xmm13, r15 + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp] + mov esi, DWORD PTR [rsp+4] + mov edi, DWORD PTR [rsp+8] + mov ebp, DWORD PTR [rsp+12] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + + xor r8, rax + movq xmm3, r8 + + movd esp, xmm4 + pextrd r15d, xmm4, 2 + movd eax, xmm8 + movd edx, xmm10 + pextrd r9d, xmm10, 2 + +CryptonightR_template_double_part3: + + movq r15, xmm13 + + mov eax, edi + mov edx, ebp + shl rdx, 32 + or rax, rdx + xor r15, rax + + mov eax, ebx + mov edx, esi + shl rdx, 32 + or rax, rdx + xor r13, rax + + movq rsp, xmm0 + mov DWORD PTR [rsp], ebx + mov DWORD PTR [rsp+4], esi + mov DWORD PTR [rsp+8], edi + mov DWORD PTR [rsp+12], ebp + + movq rbx, xmm1 + movq rsi, xmm2 + movq rdi, xmm11 + movq rbp, xmm12 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rax, r8 + mul rdi + mov rdi, rcx + mov r8, rax + movdqu xmm1, XMMWORD PTR [rbp+rcx] + pxor xmm5, xmm1 + xor ebp, 48 + paddq xmm1, xmm8 + add r13, r8 + movdqu xmm2, XMMWORD PTR [rbp+rcx] + pxor xmm5, xmm2 + add r15, rdx + movdqu XMMWORD PTR [rbp+rcx], xmm1 + paddq xmm2, xmm4 + xor ebp, 16 + mov eax, ebp + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbp+rcx] + pxor xmm5, xmm0 + movdqu XMMWORD PTR [rbp+rcx], xmm2 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rcx], xmm0 + movq rax, xmm3 + movdqa xmm10, xmm8 + mov QWORD PTR [r10+rcx], r15 + movdqa xmm8, xmm5 + xor r15, rax + mov QWORD PTR [r10+rcx+8], r13 + mov r8d, r15d + xor r13, r9 + and r8d, 2097136 + dec r11d + jnz CryptonightR_template_double_mainloop + +CryptonightR_template_double_part4: + + mov rbx, QWORD PTR [rsp+400] + movaps xmm6, XMMWORD PTR [rsp+160] + movaps xmm7, XMMWORD PTR [rsp+176] + movaps xmm8, XMMWORD PTR [rsp+192] + movaps xmm9, XMMWORD PTR [rsp+208] + movaps xmm10, XMMWORD PTR [rsp+224] + movaps xmm11, XMMWORD PTR [rsp+240] + movaps xmm12, XMMWORD PTR [rsp+256] + movaps xmm13, XMMWORD PTR [rsp+272] + movaps xmm14, XMMWORD PTR [rsp+288] + movaps xmm15, XMMWORD PTR [rsp+304] + add rsp, 320 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + ret 0 +CryptonightR_template_double_end: diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_soft_aes_template.inc b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_soft_aes_template.inc new file mode 100644 index 000000000..feea3949c --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_soft_aes_template.inc @@ -0,0 +1,266 @@ +PUBLIC FN_PREFIX(CryptonightWOW_soft_aes_template_part1) +PUBLIC FN_PREFIX(CryptonightWOW_soft_aes_template_mainloop) +PUBLIC FN_PREFIX(CryptonightWOW_soft_aes_template_part2) +PUBLIC FN_PREFIX(CryptonightWOW_soft_aes_template_part3) +PUBLIC FN_PREFIX(CryptonightWOW_soft_aes_template_end) + +ALIGN(64) +FN_PREFIX(CryptonightWOW_soft_aes_template_part1): + mov QWORD PTR [rsp+8], rcx + push rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 232 + + mov eax, [rcx+96] + mov ebx, [rcx+100] + mov esi, [rcx+104] + mov edx, [rcx+108] + mov [rsp+144], eax + mov [rsp+148], ebx + mov [rsp+152], esi + mov [rsp+156], edx + + mov rax, QWORD PTR [rcx+48] + mov r10, rcx + xor rax, QWORD PTR [rcx+16] + mov r8, QWORD PTR [rcx+32] + xor r8, QWORD PTR [rcx] + mov r9, QWORD PTR [rcx+40] + xor r9, QWORD PTR [rcx+8] + movq xmm4, rax + mov rdx, QWORD PTR [rcx+56] + xor rdx, QWORD PTR [rcx+24] + mov r11, QWORD PTR [rcx+224] + mov rcx, QWORD PTR [rcx+88] + xor rcx, QWORD PTR [r10+72] + mov rax, QWORD PTR [r10+80] + movq xmm0, rdx + xor rax, QWORD PTR [r10+64] + + movaps XMMWORD PTR [rsp+16], xmm6 + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+48], xmm8 + movaps XMMWORD PTR [rsp+64], xmm9 + movaps XMMWORD PTR [rsp+80], xmm10 + movaps XMMWORD PTR [rsp+96], xmm11 + movaps XMMWORD PTR [rsp+112], xmm12 + movaps XMMWORD PTR [rsp+128], xmm13 + + movq xmm5, rax + + mov rax, r8 + punpcklqdq xmm4, xmm0 + and eax, 2097136 + movq xmm10, QWORD PTR [r10+96] + movq xmm0, rcx + mov rcx, QWORD PTR [r10+104] + xorps xmm9, xmm9 + mov QWORD PTR [rsp+328], rax + movq xmm12, r11 + mov QWORD PTR [rsp+320], r9 + punpcklqdq xmm5, xmm0 + movq xmm13, rcx + mov r12d, 524288 + + ALIGN(64) +FN_PREFIX(CryptonightWOW_soft_aes_template_mainloop): + movd xmm11, r12d + mov r12, QWORD PTR [r10+272] + lea r13, QWORD PTR [rax+r11] + mov esi, DWORD PTR [r13] + movq xmm0, r9 + mov r10d, DWORD PTR [r13+4] + movq xmm7, r8 + mov ebp, DWORD PTR [r13+12] + mov r14d, DWORD PTR [r13+8] + mov rdx, QWORD PTR [rsp+328] + movzx ecx, sil + shr esi, 8 + punpcklqdq xmm7, xmm0 + mov r15d, DWORD PTR [r12+rcx*4] + movzx ecx, r10b + shr r10d, 8 + mov edi, DWORD PTR [r12+rcx*4] + movzx ecx, r14b + shr r14d, 8 + mov ebx, DWORD PTR [r12+rcx*4] + movzx ecx, bpl + shr ebp, 8 + mov r9d, DWORD PTR [r12+rcx*4] + movzx ecx, r10b + shr r10d, 8 + xor r15d, DWORD PTR [r12+rcx*4+1024] + movzx ecx, r14b + shr r14d, 8 + mov eax, r14d + shr eax, 8 + xor edi, DWORD PTR [r12+rcx*4+1024] + add eax, 256 + movzx ecx, bpl + shr ebp, 8 + xor ebx, DWORD PTR [r12+rcx*4+1024] + movzx ecx, sil + shr esi, 8 + xor r9d, DWORD PTR [r12+rcx*4+1024] + add r12, 2048 + movzx ecx, r10b + shr r10d, 8 + add r10d, 256 + mov r11d, DWORD PTR [r12+rax*4] + xor r11d, DWORD PTR [r12+rcx*4] + xor r11d, r9d + movzx ecx, sil + mov r10d, DWORD PTR [r12+r10*4] + shr esi, 8 + add esi, 256 + xor r10d, DWORD PTR [r12+rcx*4] + movzx ecx, bpl + xor r10d, ebx + shr ebp, 8 + movd xmm1, r11d + add ebp, 256 + movq r11, xmm12 + mov r9d, DWORD PTR [r12+rcx*4] + xor r9d, DWORD PTR [r12+rsi*4] + mov eax, DWORD PTR [r12+rbp*4] + xor r9d, edi + movzx ecx, r14b + movd xmm0, r10d + movd xmm2, r9d + xor eax, DWORD PTR [r12+rcx*4] + mov rcx, rdx + xor eax, r15d + punpckldq xmm2, xmm1 + xor rcx, 16 + movd xmm6, eax + mov rax, rdx + punpckldq xmm6, xmm0 + xor rax, 32 + punpckldq xmm6, xmm2 + xor rdx, 48 + movdqu xmm2, XMMWORD PTR [rcx+r11] + pxor xmm6, xmm7 + paddq xmm2, xmm4 + movdqu xmm1, XMMWORD PTR [rax+r11] + movdqu xmm0, XMMWORD PTR [rdx+r11] + paddq xmm0, xmm5 + movdqu XMMWORD PTR [rcx+r11], xmm0 + movdqu XMMWORD PTR [rax+r11], xmm2 + movq rcx, xmm13 + paddq xmm1, xmm7 + movdqu XMMWORD PTR [rdx+r11], xmm1 + movq rdi, xmm6 + mov r10, rdi + and r10d, 2097136 + movdqa xmm0, xmm6 + pxor xmm0, xmm4 + movdqu XMMWORD PTR [r13], xmm0 + + mov ebx, [rsp+144] + mov ebp, [rsp+152] + add ebx, [rsp+148] + add ebp, [rsp+156] + shl rbp, 32 + or rbx, rbp + + xor rbx, QWORD PTR [r10+r11] + lea r14, QWORD PTR [r10+r11] + mov rbp, QWORD PTR [r14+8] + + mov [rsp+160], rbx + mov [rsp+168], rdi + mov [rsp+176], rbp + mov [rsp+184], r10 + mov r10, rsp + + mov ebx, [rsp+144] + mov esi, [rsp+148] + mov edi, [rsp+152] + mov ebp, [rsp+156] + + movd esp, xmm7 + movaps xmm0, xmm7 + psrldq xmm0, 8 + movd r15d, xmm0 + movd eax, xmm4 + movd edx, xmm5 + +FN_PREFIX(CryptonightWOW_soft_aes_template_part2): + mov rsp, r10 + mov [rsp+144], ebx + mov [rsp+148], esi + mov [rsp+152], edi + mov [rsp+156], ebp + + mov rbx, [rsp+160] + mov rdi, [rsp+168] + mov rbp, [rsp+176] + mov r10, [rsp+184] + + mov r9, r10 + xor r9, 16 + mov rcx, r10 + xor rcx, 32 + xor r10, 48 + mov rax, rbx + mul rdi + movdqu xmm2, XMMWORD PTR [r9+r11] + movdqu xmm1, XMMWORD PTR [rcx+r11] + paddq xmm1, xmm7 + movq xmm0, rax + movq xmm3, rdx + xor rax, QWORD PTR [r11+rcx+8] + xor rdx, QWORD PTR [rcx+r11] + punpcklqdq xmm3, xmm0 + add r8, rdx + movdqu xmm0, XMMWORD PTR [r10+r11] + pxor xmm2, xmm3 + paddq xmm0, xmm5 + paddq xmm2, xmm4 + movdqu XMMWORD PTR [r9+r11], xmm0 + movdqa xmm5, xmm4 + mov r9, QWORD PTR [rsp+320] + movdqa xmm4, xmm6 + add r9, rax + movdqu XMMWORD PTR [rcx+r11], xmm2 + movdqu XMMWORD PTR [r10+r11], xmm1 + mov r10, QWORD PTR [rsp+304] + movd r12d, xmm11 + mov QWORD PTR [r14], r8 + xor r8, rbx + mov rax, r8 + mov QWORD PTR [r14+8], r9 + and eax, 2097136 + xor r9, rbp + mov QWORD PTR [rsp+320], r9 + mov QWORD PTR [rsp+328], rax + sub r12d, 1 + jne FN_PREFIX(CryptonightWOW_soft_aes_template_mainloop) + +FN_PREFIX(CryptonightWOW_soft_aes_template_part3): + movaps xmm6, XMMWORD PTR [rsp+16] + movaps xmm7, XMMWORD PTR [rsp+32] + movaps xmm8, XMMWORD PTR [rsp+48] + movaps xmm9, XMMWORD PTR [rsp+64] + movaps xmm10, XMMWORD PTR [rsp+80] + movaps xmm11, XMMWORD PTR [rsp+96] + movaps xmm12, XMMWORD PTR [rsp+112] + movaps xmm13, XMMWORD PTR [rsp+128] + + add rsp, 232 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + pop rbx + ret +FN_PREFIX(CryptonightWOW_soft_aes_template_end): diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_soft_aes_template_win.inc b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_soft_aes_template_win.inc new file mode 100644 index 000000000..6ebad99f6 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_soft_aes_template_win.inc @@ -0,0 +1,266 @@ +PUBLIC CryptonightWOW_soft_aes_template_part1 +PUBLIC CryptonightWOW_soft_aes_template_mainloop +PUBLIC CryptonightWOW_soft_aes_template_part2 +PUBLIC CryptonightWOW_soft_aes_template_part3 +PUBLIC CryptonightWOW_soft_aes_template_end + +ALIGN(64) +CryptonightWOW_soft_aes_template_part1: + mov QWORD PTR [rsp+8], rcx + push rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 232 + + mov eax, [rcx+96] + mov ebx, [rcx+100] + mov esi, [rcx+104] + mov edx, [rcx+108] + mov [rsp+144], eax + mov [rsp+148], ebx + mov [rsp+152], esi + mov [rsp+156], edx + + mov rax, QWORD PTR [rcx+48] + mov r10, rcx + xor rax, QWORD PTR [rcx+16] + mov r8, QWORD PTR [rcx+32] + xor r8, QWORD PTR [rcx] + mov r9, QWORD PTR [rcx+40] + xor r9, QWORD PTR [rcx+8] + movq xmm4, rax + mov rdx, QWORD PTR [rcx+56] + xor rdx, QWORD PTR [rcx+24] + mov r11, QWORD PTR [rcx+224] + mov rcx, QWORD PTR [rcx+88] + xor rcx, QWORD PTR [r10+72] + mov rax, QWORD PTR [r10+80] + movq xmm0, rdx + xor rax, QWORD PTR [r10+64] + + movaps XMMWORD PTR [rsp+16], xmm6 + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+48], xmm8 + movaps XMMWORD PTR [rsp+64], xmm9 + movaps XMMWORD PTR [rsp+80], xmm10 + movaps XMMWORD PTR [rsp+96], xmm11 + movaps XMMWORD PTR [rsp+112], xmm12 + movaps XMMWORD PTR [rsp+128], xmm13 + + movq xmm5, rax + + mov rax, r8 + punpcklqdq xmm4, xmm0 + and eax, 2097136 + movq xmm10, QWORD PTR [r10+96] + movq xmm0, rcx + mov rcx, QWORD PTR [r10+104] + xorps xmm9, xmm9 + mov QWORD PTR [rsp+328], rax + movq xmm12, r11 + mov QWORD PTR [rsp+320], r9 + punpcklqdq xmm5, xmm0 + movq xmm13, rcx + mov r12d, 524288 + + ALIGN(64) +CryptonightWOW_soft_aes_template_mainloop: + movd xmm11, r12d + mov r12, QWORD PTR [r10+272] + lea r13, QWORD PTR [rax+r11] + mov esi, DWORD PTR [r13] + movq xmm0, r9 + mov r10d, DWORD PTR [r13+4] + movq xmm7, r8 + mov ebp, DWORD PTR [r13+12] + mov r14d, DWORD PTR [r13+8] + mov rdx, QWORD PTR [rsp+328] + movzx ecx, sil + shr esi, 8 + punpcklqdq xmm7, xmm0 + mov r15d, DWORD PTR [r12+rcx*4] + movzx ecx, r10b + shr r10d, 8 + mov edi, DWORD PTR [r12+rcx*4] + movzx ecx, r14b + shr r14d, 8 + mov ebx, DWORD PTR [r12+rcx*4] + movzx ecx, bpl + shr ebp, 8 + mov r9d, DWORD PTR [r12+rcx*4] + movzx ecx, r10b + shr r10d, 8 + xor r15d, DWORD PTR [r12+rcx*4+1024] + movzx ecx, r14b + shr r14d, 8 + mov eax, r14d + shr eax, 8 + xor edi, DWORD PTR [r12+rcx*4+1024] + add eax, 256 + movzx ecx, bpl + shr ebp, 8 + xor ebx, DWORD PTR [r12+rcx*4+1024] + movzx ecx, sil + shr esi, 8 + xor r9d, DWORD PTR [r12+rcx*4+1024] + add r12, 2048 + movzx ecx, r10b + shr r10d, 8 + add r10d, 256 + mov r11d, DWORD PTR [r12+rax*4] + xor r11d, DWORD PTR [r12+rcx*4] + xor r11d, r9d + movzx ecx, sil + mov r10d, DWORD PTR [r12+r10*4] + shr esi, 8 + add esi, 256 + xor r10d, DWORD PTR [r12+rcx*4] + movzx ecx, bpl + xor r10d, ebx + shr ebp, 8 + movd xmm1, r11d + add ebp, 256 + movq r11, xmm12 + mov r9d, DWORD PTR [r12+rcx*4] + xor r9d, DWORD PTR [r12+rsi*4] + mov eax, DWORD PTR [r12+rbp*4] + xor r9d, edi + movzx ecx, r14b + movd xmm0, r10d + movd xmm2, r9d + xor eax, DWORD PTR [r12+rcx*4] + mov rcx, rdx + xor eax, r15d + punpckldq xmm2, xmm1 + xor rcx, 16 + movd xmm6, eax + mov rax, rdx + punpckldq xmm6, xmm0 + xor rax, 32 + punpckldq xmm6, xmm2 + xor rdx, 48 + movdqu xmm2, XMMWORD PTR [rcx+r11] + pxor xmm6, xmm7 + paddq xmm2, xmm4 + movdqu xmm1, XMMWORD PTR [rax+r11] + movdqu xmm0, XMMWORD PTR [rdx+r11] + paddq xmm0, xmm5 + movdqu XMMWORD PTR [rcx+r11], xmm0 + movdqu XMMWORD PTR [rax+r11], xmm2 + movq rcx, xmm13 + paddq xmm1, xmm7 + movdqu XMMWORD PTR [rdx+r11], xmm1 + movq rdi, xmm6 + mov r10, rdi + and r10d, 2097136 + movdqa xmm0, xmm6 + pxor xmm0, xmm4 + movdqu XMMWORD PTR [r13], xmm0 + + mov ebx, [rsp+144] + mov ebp, [rsp+152] + add ebx, [rsp+148] + add ebp, [rsp+156] + shl rbp, 32 + or rbx, rbp + + xor rbx, QWORD PTR [r10+r11] + lea r14, QWORD PTR [r10+r11] + mov rbp, QWORD PTR [r14+8] + + mov [rsp+160], rbx + mov [rsp+168], rdi + mov [rsp+176], rbp + mov [rsp+184], r10 + mov r10, rsp + + mov ebx, [rsp+144] + mov esi, [rsp+148] + mov edi, [rsp+152] + mov ebp, [rsp+156] + + movd esp, xmm7 + movaps xmm0, xmm7 + psrldq xmm0, 8 + movd r15d, xmm0 + movd eax, xmm4 + movd edx, xmm5 + +CryptonightWOW_soft_aes_template_part2: + mov rsp, r10 + mov [rsp+144], ebx + mov [rsp+148], esi + mov [rsp+152], edi + mov [rsp+156], ebp + + mov rbx, [rsp+160] + mov rdi, [rsp+168] + mov rbp, [rsp+176] + mov r10, [rsp+184] + + mov r9, r10 + xor r9, 16 + mov rcx, r10 + xor rcx, 32 + xor r10, 48 + mov rax, rbx + mul rdi + movdqu xmm2, XMMWORD PTR [r9+r11] + movdqu xmm1, XMMWORD PTR [rcx+r11] + paddq xmm1, xmm7 + movq xmm0, rax + movq xmm3, rdx + xor rax, QWORD PTR [r11+rcx+8] + xor rdx, QWORD PTR [rcx+r11] + punpcklqdq xmm3, xmm0 + add r8, rdx + movdqu xmm0, XMMWORD PTR [r10+r11] + pxor xmm2, xmm3 + paddq xmm0, xmm5 + paddq xmm2, xmm4 + movdqu XMMWORD PTR [r9+r11], xmm0 + movdqa xmm5, xmm4 + mov r9, QWORD PTR [rsp+320] + movdqa xmm4, xmm6 + add r9, rax + movdqu XMMWORD PTR [rcx+r11], xmm2 + movdqu XMMWORD PTR [r10+r11], xmm1 + mov r10, QWORD PTR [rsp+304] + movd r12d, xmm11 + mov QWORD PTR [r14], r8 + xor r8, rbx + mov rax, r8 + mov QWORD PTR [r14+8], r9 + and eax, 2097136 + xor r9, rbp + mov QWORD PTR [rsp+320], r9 + mov QWORD PTR [rsp+328], rax + sub r12d, 1 + jne CryptonightWOW_soft_aes_template_mainloop + +CryptonightWOW_soft_aes_template_part3: + movaps xmm6, XMMWORD PTR [rsp+16] + movaps xmm7, XMMWORD PTR [rsp+32] + movaps xmm8, XMMWORD PTR [rsp+48] + movaps xmm9, XMMWORD PTR [rsp+64] + movaps xmm10, XMMWORD PTR [rsp+80] + movaps xmm11, XMMWORD PTR [rsp+96] + movaps xmm12, XMMWORD PTR [rsp+112] + movaps xmm13, XMMWORD PTR [rsp+128] + + add rsp, 232 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + pop rbx + ret +CryptonightWOW_soft_aes_template_end: diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_template_win.inc b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_template_win.inc new file mode 100644 index 000000000..c5652e278 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/CryptonightWOW_template_win.inc @@ -0,0 +1,486 @@ +PUBLIC CryptonightWOW_template_part1 +PUBLIC CryptonightWOW_template_mainloop +PUBLIC CryptonightWOW_template_part2 +PUBLIC CryptonightWOW_template_part3 +PUBLIC CryptonightWOW_template_end +PUBLIC CryptonightWOW_template_double_part1 +PUBLIC CryptonightWOW_template_double_mainloop +PUBLIC CryptonightWOW_template_double_part2 +PUBLIC CryptonightWOW_template_double_part3 +PUBLIC CryptonightWOW_template_double_part4 +PUBLIC CryptonightWOW_template_double_end + +ALIGN(64) +CryptonightWOW_template_part1: + mov QWORD PTR [rsp+16], rbx + mov QWORD PTR [rsp+24], rbp + mov QWORD PTR [rsp+32], rsi + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + push rdi + sub rsp, 64 + mov r12, rcx + mov r8, QWORD PTR [r12+32] + mov rdx, r12 + xor r8, QWORD PTR [r12] + mov r15, QWORD PTR [r12+40] + mov r9, r8 + xor r15, QWORD PTR [r12+8] + mov r11, QWORD PTR [r12+224] + mov r12, QWORD PTR [r12+56] + xor r12, QWORD PTR [rdx+24] + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + movaps XMMWORD PTR [rsp+48], xmm6 + movq xmm0, r12 + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+16], xmm8 + movaps XMMWORD PTR [rsp], xmm9 + mov r12, QWORD PTR [rdx+88] + xor r12, QWORD PTR [rdx+72] + movq xmm6, rax + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm6, xmm0 + and r9d, 2097136 + movq xmm0, r12 + movq xmm7, rax + punpcklqdq xmm7, xmm0 + mov r10d, r9d + movq xmm9, rsp + mov rsp, r8 + mov r8d, 524288 + + mov ebx, [rdx+96] + mov esi, [rdx+100] + mov edi, [rdx+104] + mov ebp, [rdx+108] + + ALIGN(64) +CryptonightWOW_template_mainloop: + movdqa xmm5, XMMWORD PTR [r9+r11] + movq xmm0, r15 + movq xmm4, rsp + punpcklqdq xmm4, xmm0 + lea rdx, QWORD PTR [r9+r11] + + aesenc xmm5, xmm4 + movd r10d, xmm5 + and r10d, 2097136 + + mov r12d, r9d + mov eax, r9d + xor r9d, 48 + xor r12d, 16 + xor eax, 32 + movdqu xmm0, XMMWORD PTR [r9+r11] + movdqu xmm2, XMMWORD PTR [r12+r11] + movdqu xmm1, XMMWORD PTR [rax+r11] + paddq xmm0, xmm7 + paddq xmm2, xmm6 + paddq xmm1, xmm4 + movdqu XMMWORD PTR [r12+r11], xmm0 + movq r12, xmm5 + movdqu XMMWORD PTR [rax+r11], xmm2 + movdqu XMMWORD PTR [r9+r11], xmm1 + + movdqa xmm0, xmm5 + pxor xmm0, xmm6 + movdqu XMMWORD PTR [rdx], xmm0 + + lea r13d, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or r13, rdx + + xor r13, QWORD PTR [r10+r11] + mov r14, QWORD PTR [r10+r11+8] + + movd eax, xmm6 + movd edx, xmm7 + pextrd r9d, xmm7, 2 + +CryptonightWOW_template_part2: + mov rax, r13 + mul r12 + movq xmm0, rax + movq xmm3, rdx + punpcklqdq xmm3, xmm0 + + mov r9d, r10d + mov r12d, r10d + xor r9d, 16 + xor r12d, 32 + xor r10d, 48 + movdqa xmm1, XMMWORD PTR [r12+r11] + xor rdx, QWORD PTR [r12+r11] + xor rax, QWORD PTR [r11+r12+8] + movdqa xmm2, XMMWORD PTR [r9+r11] + pxor xmm3, xmm2 + paddq xmm7, XMMWORD PTR [r10+r11] + paddq xmm1, xmm4 + paddq xmm3, xmm6 + movdqu XMMWORD PTR [r9+r11], xmm7 + movdqu XMMWORD PTR [r12+r11], xmm3 + movdqu XMMWORD PTR [r10+r11], xmm1 + + movdqa xmm7, xmm6 + add r15, rax + add rsp, rdx + xor r10, 48 + mov QWORD PTR [r10+r11], rsp + xor rsp, r13 + mov r9d, esp + mov QWORD PTR [r10+r11+8], r15 + and r9d, 2097136 + xor r15, r14 + movdqa xmm6, xmm5 + dec r8d + jnz CryptonightWOW_template_mainloop + +CryptonightWOW_template_part3: + movq rsp, xmm9 + + mov rbx, QWORD PTR [rsp+136] + mov rbp, QWORD PTR [rsp+144] + mov rsi, QWORD PTR [rsp+152] + movaps xmm6, XMMWORD PTR [rsp+48] + movaps xmm7, XMMWORD PTR [rsp+32] + movaps xmm8, XMMWORD PTR [rsp+16] + movaps xmm9, XMMWORD PTR [rsp] + add rsp, 64 + pop rdi + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + ret 0 +CryptonightWOW_template_end: + +ALIGN(64) +CryptonightWOW_template_double_part1: + mov QWORD PTR [rsp+24], rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 320 + mov r14, QWORD PTR [rcx+32] + mov r8, rcx + xor r14, QWORD PTR [rcx] + mov r12, QWORD PTR [rcx+40] + mov ebx, r14d + mov rsi, QWORD PTR [rcx+224] + and ebx, 2097136 + xor r12, QWORD PTR [rcx+8] + mov rcx, QWORD PTR [rcx+56] + xor rcx, QWORD PTR [r8+24] + mov rax, QWORD PTR [r8+48] + xor rax, QWORD PTR [r8+16] + mov r15, QWORD PTR [rdx+32] + xor r15, QWORD PTR [rdx] + movq xmm0, rcx + mov rcx, QWORD PTR [r8+88] + xor rcx, QWORD PTR [r8+72] + mov r13, QWORD PTR [rdx+40] + mov rdi, QWORD PTR [rdx+224] + xor r13, QWORD PTR [rdx+8] + movaps XMMWORD PTR [rsp+160], xmm6 + movaps XMMWORD PTR [rsp+176], xmm7 + movaps XMMWORD PTR [rsp+192], xmm8 + movaps XMMWORD PTR [rsp+208], xmm9 + movaps XMMWORD PTR [rsp+224], xmm10 + movaps XMMWORD PTR [rsp+240], xmm11 + movaps XMMWORD PTR [rsp+256], xmm12 + movaps XMMWORD PTR [rsp+272], xmm13 + movaps XMMWORD PTR [rsp+288], xmm14 + movaps XMMWORD PTR [rsp+304], xmm15 + movq xmm7, rax + mov rax, QWORD PTR [r8+80] + xor rax, QWORD PTR [r8+64] + + movaps xmm1, XMMWORD PTR [rdx+96] + movaps xmm2, XMMWORD PTR [r8+96] + movaps XMMWORD PTR [rsp], xmm1 + movaps XMMWORD PTR [rsp+16], xmm2 + + mov r8d, r15d + punpcklqdq xmm7, xmm0 + movq xmm0, rcx + mov rcx, QWORD PTR [rdx+56] + xor rcx, QWORD PTR [rdx+24] + movq xmm9, rax + mov QWORD PTR [rsp+128], rsi + mov rax, QWORD PTR [rdx+48] + xor rax, QWORD PTR [rdx+16] + punpcklqdq xmm9, xmm0 + movq xmm0, rcx + mov rcx, QWORD PTR [rdx+88] + xor rcx, QWORD PTR [rdx+72] + movq xmm8, rax + mov QWORD PTR [rsp+136], rdi + mov rax, QWORD PTR [rdx+80] + xor rax, QWORD PTR [rdx+64] + punpcklqdq xmm8, xmm0 + and r8d, 2097136 + movq xmm0, rcx + mov r11d, 524288 + movq xmm10, rax + punpcklqdq xmm10, xmm0 + + movq xmm14, QWORD PTR [rsp+128] + movq xmm15, QWORD PTR [rsp+136] + + ALIGN(64) +CryptonightWOW_template_double_mainloop: + movdqu xmm6, XMMWORD PTR [rbx+rsi] + movq xmm0, r12 + mov ecx, ebx + movq xmm3, r14 + punpcklqdq xmm3, xmm0 + xor ebx, 16 + aesenc xmm6, xmm3 + movq rdx, xmm6 + movq xmm4, r15 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + xor ebx, 48 + paddq xmm0, xmm7 + movdqu xmm1, XMMWORD PTR [rbx+rsi] + movdqu XMMWORD PTR [rbx+rsi], xmm0 + paddq xmm1, xmm3 + xor ebx, 16 + mov eax, ebx + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbx+rsi] + movdqu XMMWORD PTR [rbx+rsi], xmm1 + paddq xmm0, xmm9 + movdqu XMMWORD PTR [rax+rsi], xmm0 + movdqa xmm0, xmm6 + pxor xmm0, xmm7 + movdqu XMMWORD PTR [rcx+rsi], xmm0 + mov esi, edx + movdqu xmm5, XMMWORD PTR [r8+rdi] + and esi, 2097136 + mov ecx, r8d + movq xmm0, r13 + punpcklqdq xmm4, xmm0 + xor r8d, 16 + aesenc xmm5, xmm4 + movdqu xmm0, XMMWORD PTR [r8+rdi] + xor r8d, 48 + paddq xmm0, xmm8 + movdqu xmm1, XMMWORD PTR [r8+rdi] + movdqu XMMWORD PTR [r8+rdi], xmm0 + paddq xmm1, xmm4 + xor r8d, 16 + mov eax, r8d + xor rax, 32 + movdqu xmm0, XMMWORD PTR [r8+rdi] + movdqu XMMWORD PTR [r8+rdi], xmm1 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rdi], xmm0 + movdqa xmm0, xmm5 + pxor xmm0, xmm8 + movdqu XMMWORD PTR [rcx+rdi], xmm0 + movq rdi, xmm5 + movq rcx, xmm14 + mov ebp, edi + mov r8, QWORD PTR [rcx+rsi] + mov r10, QWORD PTR [rcx+rsi+8] + lea r9, QWORD PTR [rcx+rsi] + xor esi, 16 + + movq xmm0, rsp + movq xmm1, rsi + movq xmm2, rdi + movq xmm11, rbp + movq xmm12, r15 + movq xmm13, rdx + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp+16] + mov esi, DWORD PTR [rsp+20] + mov edi, DWORD PTR [rsp+24] + mov ebp, DWORD PTR [rsp+28] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + xor r8, rax + + movd esp, xmm3 + pextrd r15d, xmm3, 2 + movd eax, xmm7 + movd edx, xmm9 + pextrd r9d, xmm9, 2 + +CryptonightWOW_template_double_part2: + + movq rsp, xmm0 + mov DWORD PTR [rsp+16], ebx + mov DWORD PTR [rsp+20], esi + mov DWORD PTR [rsp+24], edi + mov DWORD PTR [rsp+28], ebp + + movq rsi, xmm1 + movq rdi, xmm2 + movq rbp, xmm11 + movq r15, xmm12 + movq rdx, xmm13 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rbx, r8 + mov rax, r8 + mul rdx + and ebp, 2097136 + mov r8, rax + movq xmm1, rdx + movq xmm0, r8 + punpcklqdq xmm1, xmm0 + pxor xmm1, XMMWORD PTR [rcx+rsi] + xor esi, 48 + paddq xmm1, xmm7 + movdqu xmm2, XMMWORD PTR [rsi+rcx] + xor rdx, QWORD PTR [rsi+rcx] + paddq xmm2, xmm3 + xor r8, QWORD PTR [rsi+rcx+8] + movdqu XMMWORD PTR [rsi+rcx], xmm1 + xor esi, 16 + mov eax, esi + mov rsi, rcx + movdqu xmm0, XMMWORD PTR [rax+rcx] + movdqu XMMWORD PTR [rax+rcx], xmm2 + paddq xmm0, xmm9 + add r12, r8 + xor rax, 32 + add r14, rdx + movdqa xmm9, xmm7 + movdqa xmm7, xmm6 + movdqu XMMWORD PTR [rax+rcx], xmm0 + mov QWORD PTR [r9+8], r12 + xor r12, r10 + mov QWORD PTR [r9], r14 + movq rcx, xmm15 + xor r14, rbx + mov r10d, ebp + mov ebx, r14d + xor ebp, 16 + and ebx, 2097136 + mov r8, QWORD PTR [r10+rcx] + mov r9, QWORD PTR [r10+rcx+8] + + movq xmm0, rsp + movq xmm1, rbx + movq xmm2, rsi + movq xmm11, rdi + movq xmm12, rbp + movq xmm13, r15 + mov [rsp+104], rcx + mov [rsp+112], r9 + + mov ebx, DWORD PTR [rsp] + mov esi, DWORD PTR [rsp+4] + mov edi, DWORD PTR [rsp+8] + mov ebp, DWORD PTR [rsp+12] + + lea eax, [ebx+esi] + lea edx, [edi+ebp] + shl rdx, 32 + or rax, rdx + + xor r8, rax + movq xmm3, r8 + + movd esp, xmm4 + pextrd r15d, xmm4, 2 + movd eax, xmm8 + movd edx, xmm10 + pextrd r9d, xmm10, 2 + +CryptonightWOW_template_double_part3: + + movq rsp, xmm0 + mov DWORD PTR [rsp], ebx + mov DWORD PTR [rsp+4], esi + mov DWORD PTR [rsp+8], edi + mov DWORD PTR [rsp+12], ebp + + movq rbx, xmm1 + movq rsi, xmm2 + movq rdi, xmm11 + movq rbp, xmm12 + movq r15, xmm13 + mov rcx, [rsp+104] + mov r9, [rsp+112] + + mov rax, r8 + mul rdi + movq xmm1, rdx + movq xmm0, rax + punpcklqdq xmm1, xmm0 + mov rdi, rcx + mov r8, rax + pxor xmm1, XMMWORD PTR [rbp+rcx] + xor ebp, 48 + paddq xmm1, xmm8 + xor r8, QWORD PTR [rbp+rcx+8] + xor rdx, QWORD PTR [rbp+rcx] + add r13, r8 + movdqu xmm2, XMMWORD PTR [rbp+rcx] + add r15, rdx + movdqu XMMWORD PTR [rbp+rcx], xmm1 + paddq xmm2, xmm4 + xor ebp, 16 + mov eax, ebp + xor rax, 32 + movdqu xmm0, XMMWORD PTR [rbp+rcx] + movdqu XMMWORD PTR [rbp+rcx], xmm2 + paddq xmm0, xmm10 + movdqu XMMWORD PTR [rax+rcx], xmm0 + movq rax, xmm3 + movdqa xmm10, xmm8 + mov QWORD PTR [r10+rcx], r15 + movdqa xmm8, xmm5 + xor r15, rax + mov QWORD PTR [r10+rcx+8], r13 + mov r8d, r15d + xor r13, r9 + and r8d, 2097136 + dec r11d + jnz CryptonightWOW_template_double_mainloop + +CryptonightWOW_template_double_part4: + + mov rbx, QWORD PTR [rsp+400] + movaps xmm6, XMMWORD PTR [rsp+160] + movaps xmm7, XMMWORD PTR [rsp+176] + movaps xmm8, XMMWORD PTR [rsp+192] + movaps xmm9, XMMWORD PTR [rsp+208] + movaps xmm10, XMMWORD PTR [rsp+224] + movaps xmm11, XMMWORD PTR [rsp+240] + movaps xmm12, XMMWORD PTR [rsp+256] + movaps xmm13, XMMWORD PTR [rsp+272] + movaps xmm14, XMMWORD PTR [rsp+288] + movaps xmm15, XMMWORD PTR [rsp+304] + add rsp, 320 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + ret 0 +CryptonightWOW_template_double_end: diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_rwz_double_main_loop.inc b/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_rwz_double_main_loop.inc new file mode 100644 index 000000000..d2d871732 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_rwz_double_main_loop.inc @@ -0,0 +1,410 @@ + mov rax, rsp + push rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 184 + + stmxcsr DWORD PTR [rsp+272] + mov DWORD PTR [rsp+276], 24448 + ldmxcsr DWORD PTR [rsp+276] + + mov r13, QWORD PTR [rcx+224] + mov r9, rdx + mov r10, QWORD PTR [rcx+32] + mov r8, rcx + xor r10, QWORD PTR [rcx] + mov r14d, 393216 + mov r11, QWORD PTR [rcx+40] + xor r11, QWORD PTR [rcx+8] + mov rsi, QWORD PTR [rdx+224] + mov rdx, QWORD PTR [rcx+56] + xor rdx, QWORD PTR [rcx+24] + mov rdi, QWORD PTR [r9+32] + xor rdi, QWORD PTR [r9] + mov rbp, QWORD PTR [r9+40] + xor rbp, QWORD PTR [r9+8] + movq xmm0, rdx + movaps XMMWORD PTR [rax-88], xmm6 + movaps XMMWORD PTR [rax-104], xmm7 + movaps XMMWORD PTR [rax-120], xmm8 + movaps XMMWORD PTR [rsp+112], xmm9 + movaps XMMWORD PTR [rsp+96], xmm10 + movaps XMMWORD PTR [rsp+80], xmm11 + movaps XMMWORD PTR [rsp+64], xmm12 + movaps XMMWORD PTR [rsp+48], xmm13 + movaps XMMWORD PTR [rsp+32], xmm14 + movaps XMMWORD PTR [rsp+16], xmm15 + mov rdx, r10 + movq xmm4, QWORD PTR [r8+96] + and edx, 2097136 + mov rax, QWORD PTR [rcx+48] + xorps xmm13, xmm13 + xor rax, QWORD PTR [rcx+16] + mov rcx, QWORD PTR [rcx+88] + xor rcx, QWORD PTR [r8+72] + movq xmm5, QWORD PTR [r8+104] + movq xmm7, rax + + mov eax, 1 + shl rax, 52 + movq xmm14, rax + punpcklqdq xmm14, xmm14 + + mov eax, 1023 + shl rax, 52 + movq xmm12, rax + punpcklqdq xmm12, xmm12 + + mov rax, QWORD PTR [r8+80] + xor rax, QWORD PTR [r8+64] + punpcklqdq xmm7, xmm0 + movq xmm0, rcx + mov rcx, QWORD PTR [r9+56] + xor rcx, QWORD PTR [r9+24] + movq xmm3, rax + mov rax, QWORD PTR [r9+48] + xor rax, QWORD PTR [r9+16] + punpcklqdq xmm3, xmm0 + movq xmm0, rcx + mov QWORD PTR [rsp], r13 + mov rcx, QWORD PTR [r9+88] + xor rcx, QWORD PTR [r9+72] + movq xmm6, rax + mov rax, QWORD PTR [r9+80] + xor rax, QWORD PTR [r9+64] + punpcklqdq xmm6, xmm0 + movq xmm0, rcx + mov QWORD PTR [rsp+256], r10 + mov rcx, rdi + mov QWORD PTR [rsp+264], r11 + movq xmm8, rax + and ecx, 2097136 + punpcklqdq xmm8, xmm0 + movq xmm0, QWORD PTR [r9+96] + punpcklqdq xmm4, xmm0 + movq xmm0, QWORD PTR [r9+104] + lea r8, QWORD PTR [rcx+rsi] + movdqu xmm11, XMMWORD PTR [r8] + punpcklqdq xmm5, xmm0 + lea r9, QWORD PTR [rdx+r13] + movdqu xmm15, XMMWORD PTR [r9] + + ALIGN(64) +rwz_main_loop_double: + movdqu xmm9, xmm15 + mov eax, edx + mov ebx, edx + xor eax, 16 + xor ebx, 32 + xor edx, 48 + + movq xmm0, r11 + movq xmm2, r10 + punpcklqdq xmm2, xmm0 + aesenc xmm9, xmm2 + + movdqu xmm0, XMMWORD PTR [rdx+r13] + movdqu xmm1, XMMWORD PTR [rbx+r13] + paddq xmm0, xmm7 + paddq xmm1, xmm2 + movdqu XMMWORD PTR [rbx+r13], xmm0 + movdqu xmm0, XMMWORD PTR [rax+r13] + movdqu XMMWORD PTR [rdx+r13], xmm1 + paddq xmm0, xmm3 + movdqu XMMWORD PTR [rax+r13], xmm0 + + movq r11, xmm9 + mov edx, r11d + and edx, 2097136 + movdqa xmm0, xmm9 + pxor xmm0, xmm7 + movdqu XMMWORD PTR [r9], xmm0 + + lea rbx, QWORD PTR [rdx+r13] + mov r10, QWORD PTR [rdx+r13] + + movdqu xmm10, xmm11 + movq xmm0, rbp + movq xmm11, rdi + punpcklqdq xmm11, xmm0 + aesenc xmm10, xmm11 + + mov eax, ecx + mov r12d, ecx + xor eax, 16 + xor r12d, 32 + xor ecx, 48 + + movdqu xmm0, XMMWORD PTR [rcx+rsi] + paddq xmm0, xmm6 + movdqu xmm1, XMMWORD PTR [r12+rsi] + movdqu XMMWORD PTR [r12+rsi], xmm0 + paddq xmm1, xmm11 + movdqu xmm0, XMMWORD PTR [rax+rsi] + movdqu XMMWORD PTR [rcx+rsi], xmm1 + paddq xmm0, xmm8 + movdqu XMMWORD PTR [rax+rsi], xmm0 + + movq rcx, xmm10 + and ecx, 2097136 + + movdqa xmm0, xmm10 + pxor xmm0, xmm6 + movdqu XMMWORD PTR [r8], xmm0 + mov r12, QWORD PTR [rcx+rsi] + + mov r9, QWORD PTR [rbx+8] + + xor edx, 16 + mov r8d, edx + mov r15d, edx + + movq rdx, xmm5 + shl rdx, 32 + movq rax, xmm4 + xor rdx, rax + xor r10, rdx + mov rax, r10 + mul r11 + mov r11d, r8d + xor r11d, 48 + movq xmm0, rdx + xor rdx, [r11+r13] + movq xmm1, rax + xor rax, [r11+r13+8] + punpcklqdq xmm0, xmm1 + + pxor xmm0, XMMWORD PTR [r8+r13] + movdqu xmm1, XMMWORD PTR [r11+r13] + paddq xmm0, xmm3 + paddq xmm1, xmm2 + movdqu XMMWORD PTR [r8+r13], xmm0 + xor r8d, 32 + movdqu xmm0, XMMWORD PTR [r8+r13] + movdqu XMMWORD PTR [r8+r13], xmm1 + paddq xmm0, xmm7 + movdqu XMMWORD PTR [r11+r13], xmm0 + + mov r11, QWORD PTR [rsp+256] + add r11, rdx + mov rdx, QWORD PTR [rsp+264] + add rdx, rax + mov QWORD PTR [rbx], r11 + xor r11, r10 + mov QWORD PTR [rbx+8], rdx + xor rdx, r9 + mov QWORD PTR [rsp+256], r11 + and r11d, 2097136 + mov QWORD PTR [rsp+264], rdx + mov QWORD PTR [rsp+8], r11 + lea r15, QWORD PTR [r11+r13] + movdqu xmm15, XMMWORD PTR [r11+r13] + lea r13, QWORD PTR [rsi+rcx] + movdqa xmm0, xmm5 + psrldq xmm0, 8 + movaps xmm2, xmm13 + movq r10, xmm0 + psllq xmm5, 1 + shl r10, 32 + movdqa xmm0, xmm9 + psrldq xmm0, 8 + movdqa xmm1, xmm10 + movq r11, xmm0 + psrldq xmm1, 8 + movq r8, xmm1 + psrldq xmm4, 8 + movaps xmm0, xmm13 + movq rax, xmm4 + xor r10, rax + movaps xmm1, xmm13 + xor r10, r12 + lea rax, QWORD PTR [r11+1] + shr rax, 1 + movdqa xmm3, xmm9 + punpcklqdq xmm3, xmm10 + paddq xmm5, xmm3 + movq rdx, xmm5 + psrldq xmm5, 8 + cvtsi2sd xmm2, rax + or edx, -2147483647 + lea rax, QWORD PTR [r8+1] + shr rax, 1 + movq r9, xmm5 + cvtsi2sd xmm0, rax + or r9d, -2147483647 + cvtsi2sd xmm1, rdx + unpcklpd xmm2, xmm0 + movaps xmm0, xmm13 + cvtsi2sd xmm0, r9 + unpcklpd xmm1, xmm0 + divpd xmm2, xmm1 + paddq xmm2, xmm14 + cvttsd2si rax, xmm2 + psrldq xmm2, 8 + mov rbx, rax + imul rax, rdx + sub r11, rax + js rwz_div_fix_1 +rwz_div_fix_1_ret: + + cvttsd2si rdx, xmm2 + mov rax, rdx + imul rax, r9 + movd xmm2, r11d + movd xmm4, ebx + sub r8, rax + js rwz_div_fix_2 +rwz_div_fix_2_ret: + + movd xmm1, r8d + movd xmm0, edx + punpckldq xmm2, xmm1 + punpckldq xmm4, xmm0 + punpckldq xmm4, xmm2 + paddq xmm3, xmm4 + movdqa xmm0, xmm3 + psrlq xmm0, 12 + paddq xmm0, xmm12 + sqrtpd xmm1, xmm0 + movq r9, xmm1 + movdqa xmm5, xmm1 + psrlq xmm5, 19 + test r9, 524287 + je rwz_sqrt_fix_1 +rwz_sqrt_fix_1_ret: + + movq r9, xmm10 + psrldq xmm1, 8 + movq r8, xmm1 + test r8, 524287 + je rwz_sqrt_fix_2 +rwz_sqrt_fix_2_ret: + + mov r12d, ecx + mov r8d, ecx + xor r12d, 16 + xor r8d, 32 + xor ecx, 48 + mov rax, r10 + mul r9 + movq xmm0, rax + movq xmm3, rdx + punpcklqdq xmm3, xmm0 + + movdqu xmm0, XMMWORD PTR [r12+rsi] + pxor xmm0, xmm3 + movdqu xmm1, XMMWORD PTR [r8+rsi] + xor rdx, [r8+rsi] + xor rax, [r8+rsi+8] + movdqu xmm3, XMMWORD PTR [rcx+rsi] + paddq xmm3, xmm6 + paddq xmm1, xmm11 + paddq xmm0, xmm8 + movdqu XMMWORD PTR [r8+rsi], xmm3 + movdqu XMMWORD PTR [rcx+rsi], xmm1 + movdqu XMMWORD PTR [r12+rsi], xmm0 + + add rdi, rdx + mov QWORD PTR [r13], rdi + xor rdi, r10 + mov ecx, edi + and ecx, 2097136 + lea r8, QWORD PTR [rcx+rsi] + + mov rdx, QWORD PTR [r13+8] + add rbp, rax + mov QWORD PTR [r13+8], rbp + movdqu xmm11, XMMWORD PTR [rcx+rsi] + xor rbp, rdx + mov r13, QWORD PTR [rsp] + movdqa xmm3, xmm7 + mov rdx, QWORD PTR [rsp+8] + movdqa xmm8, xmm6 + mov r10, QWORD PTR [rsp+256] + movdqa xmm7, xmm9 + mov r11, QWORD PTR [rsp+264] + movdqa xmm6, xmm10 + mov r9, r15 + dec r14d + jne rwz_main_loop_double + + ldmxcsr DWORD PTR [rsp+272] + movaps xmm13, XMMWORD PTR [rsp+48] + lea r11, QWORD PTR [rsp+184] + movaps xmm6, XMMWORD PTR [r11-24] + movaps xmm7, XMMWORD PTR [r11-40] + movaps xmm8, XMMWORD PTR [r11-56] + movaps xmm9, XMMWORD PTR [r11-72] + movaps xmm10, XMMWORD PTR [r11-88] + movaps xmm11, XMMWORD PTR [r11-104] + movaps xmm12, XMMWORD PTR [r11-120] + movaps xmm14, XMMWORD PTR [rsp+32] + movaps xmm15, XMMWORD PTR [rsp+16] + mov rsp, r11 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + pop rbx + jmp rwz_cnv2_double_mainloop_asm_endp + +rwz_div_fix_1: + dec rbx + add r11, rdx + jmp rwz_div_fix_1_ret + +rwz_div_fix_2: + dec rdx + add r8, r9 + jmp rwz_div_fix_2_ret + +rwz_sqrt_fix_1: + movq r8, xmm3 + movdqa xmm0, xmm5 + psrldq xmm0, 8 + dec r9 + mov r11d, -1022 + shl r11, 32 + mov rax, r9 + shr r9, 19 + shr rax, 20 + mov rdx, r9 + sub rdx, rax + lea rdx, [rdx+r11+1] + add rax, r11 + imul rdx, rax + sub rdx, r8 + adc r9, 0 + movq xmm5, r9 + punpcklqdq xmm5, xmm0 + jmp rwz_sqrt_fix_1_ret + +rwz_sqrt_fix_2: + psrldq xmm3, 8 + movq r11, xmm3 + dec r8 + mov ebx, -1022 + shl rbx, 32 + mov rax, r8 + shr r8, 19 + shr rax, 20 + mov rdx, r8 + sub rdx, rax + lea rdx, [rdx+rbx+1] + add rax, rbx + imul rdx, rax + sub rdx, r11 + adc r8, 0 + movq xmm0, r8 + punpcklqdq xmm5, xmm0 + jmp rwz_sqrt_fix_2_ret + +rwz_cnv2_double_mainloop_asm_endp: diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_rwz_main_loop.inc b/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_rwz_main_loop.inc new file mode 100644 index 000000000..021f787e3 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/cn2/cnv2_rwz_main_loop.inc @@ -0,0 +1,186 @@ + mov QWORD PTR [rsp+24], rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 80 + + stmxcsr DWORD PTR [rsp] + mov DWORD PTR [rsp+4], 24448 + ldmxcsr DWORD PTR [rsp+4] + + mov rax, QWORD PTR [rcx+48] + mov r9, rcx + xor rax, QWORD PTR [rcx+16] + mov esi, 393216 + mov r8, QWORD PTR [rcx+32] + mov r13d, -2147483647 + xor r8, QWORD PTR [rcx] + mov r11, QWORD PTR [rcx+40] + mov r10, r8 + mov rdx, QWORD PTR [rcx+56] + movq xmm4, rax + xor rdx, QWORD PTR [rcx+24] + xor r11, QWORD PTR [rcx+8] + mov rbx, QWORD PTR [rcx+224] + mov rax, QWORD PTR [r9+80] + xor rax, QWORD PTR [r9+64] + movq xmm0, rdx + mov rcx, QWORD PTR [rcx+88] + xor rcx, QWORD PTR [r9+72] + movq xmm3, QWORD PTR [r9+104] + movaps XMMWORD PTR [rsp+64], xmm6 + movaps XMMWORD PTR [rsp+48], xmm7 + movaps XMMWORD PTR [rsp+32], xmm8 + and r10d, 2097136 + movq xmm5, rax + + xor eax, eax + mov QWORD PTR [rsp+16], rax + + mov ax, 1023 + shl rax, 52 + movq xmm8, rax + mov r15, QWORD PTR [r9+96] + punpcklqdq xmm4, xmm0 + movq xmm0, rcx + punpcklqdq xmm5, xmm0 + movdqu xmm6, XMMWORD PTR [r10+rbx] + + ALIGN(64) +rwz_main_loop: + lea rdx, QWORD PTR [r10+rbx] + mov ecx, r10d + mov eax, r10d + mov rdi, r15 + xor ecx, 16 + xor eax, 32 + xor r10d, 48 + movq xmm0, r11 + movq xmm7, r8 + punpcklqdq xmm7, xmm0 + aesenc xmm6, xmm7 + movq rbp, xmm6 + mov r9, rbp + and r9d, 2097136 + movdqu xmm0, XMMWORD PTR [rcx+rbx] + movdqu xmm1, XMMWORD PTR [rax+rbx] + movdqu xmm2, XMMWORD PTR [r10+rbx] + paddq xmm0, xmm5 + paddq xmm1, xmm7 + paddq xmm2, xmm4 + movdqu XMMWORD PTR [rcx+rbx], xmm0 + movdqu XMMWORD PTR [rax+rbx], xmm2 + movdqu XMMWORD PTR [r10+rbx], xmm1 + mov r10, r9 + xor r10d, 32 + movq rcx, xmm3 + mov rax, rcx + shl rax, 32 + xor rdi, rax + movdqa xmm0, xmm6 + pxor xmm0, xmm4 + movdqu XMMWORD PTR [rdx], xmm0 + xor rdi, QWORD PTR [r9+rbx] + lea r14, QWORD PTR [r9+rbx] + mov r12, QWORD PTR [r14+8] + xor edx, edx + lea r9d, DWORD PTR [ecx+ecx] + add r9d, ebp + movdqa xmm0, xmm6 + psrldq xmm0, 8 + or r9d, r13d + movq rax, xmm0 + div r9 + xorps xmm3, xmm3 + mov eax, eax + shl rdx, 32 + add rdx, rax + lea r9, QWORD PTR [rdx+rbp] + mov r15, rdx + mov rax, r9 + shr rax, 12 + movq xmm0, rax + paddq xmm0, xmm8 + sqrtsd xmm3, xmm0 + psubq xmm3, XMMWORD PTR [rsp+16] + movq rdx, xmm3 + test edx, 524287 + je rwz_sqrt_fixup + psrlq xmm3, 19 +rwz_sqrt_fixup_ret: + + mov ecx, r10d + mov rax, rdi + mul rbp + movq xmm2, rdx + xor rdx, [rcx+rbx] + add r8, rdx + mov QWORD PTR [r14], r8 + xor r8, rdi + mov edi, r8d + and edi, 2097136 + movq xmm0, rax + xor rax, [rcx+rbx+8] + add r11, rax + mov QWORD PTR [r14+8], r11 + punpcklqdq xmm2, xmm0 + + mov r9d, r10d + xor r9d, 48 + xor r10d, 16 + pxor xmm2, XMMWORD PTR [r9+rbx] + movdqu xmm0, XMMWORD PTR [r10+rbx] + paddq xmm0, xmm4 + movdqu xmm1, XMMWORD PTR [rcx+rbx] + paddq xmm2, xmm5 + paddq xmm1, xmm7 + movdqa xmm5, xmm4 + movdqu XMMWORD PTR [r9+rbx], xmm2 + movdqa xmm4, xmm6 + movdqu XMMWORD PTR [rcx+rbx], xmm0 + movdqu XMMWORD PTR [r10+rbx], xmm1 + movdqu xmm6, [rdi+rbx] + mov r10d, edi + xor r11, r12 + dec rsi + jne rwz_main_loop + + ldmxcsr DWORD PTR [rsp] + mov rbx, QWORD PTR [rsp+160] + movaps xmm6, XMMWORD PTR [rsp+64] + movaps xmm7, XMMWORD PTR [rsp+48] + movaps xmm8, XMMWORD PTR [rsp+32] + add rsp, 80 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + jmp cnv2_rwz_main_loop_endp + +rwz_sqrt_fixup: + dec rdx + mov r13d, -1022 + shl r13, 32 + mov rax, rdx + shr rdx, 19 + shr rax, 20 + mov rcx, rdx + sub rcx, rax + add rax, r13 + not r13 + sub rcx, r13 + mov r13d, -2147483647 + imul rcx, rax + sub rcx, r9 + adc rdx, 0 + movq xmm3, rdx + jmp rwz_sqrt_fixup_ret + +cnv2_rwz_main_loop_endp: diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/cn_main_loop.S b/src/Native/libcryptonight/xmrig/crypto/asm/cn_main_loop.S index a792337f0..c2c08739a 100644 --- a/src/Native/libcryptonight/xmrig/crypto/asm/cn_main_loop.S +++ b/src/Native/libcryptonight/xmrig/crypto/asm/cn_main_loop.S @@ -15,6 +15,8 @@ .global FN_PREFIX(cnv2_mainloop_ryzen_asm) .global FN_PREFIX(cnv2_mainloop_bulldozer_asm) .global FN_PREFIX(cnv2_double_mainloop_sandybridge_asm) +.global FN_PREFIX(cnv2_rwz_mainloop_asm) +.global FN_PREFIX(cnv2_rwz_double_mainloop_asm) ALIGN(64) FN_PREFIX(cnv2_mainloop_ivybridge_asm): @@ -52,3 +54,21 @@ FN_PREFIX(cnv2_double_mainloop_sandybridge_asm): add rsp, 48 ret 0 mov eax, 3735929054 + +ALIGN(64) +FN_PREFIX(cnv2_rwz_mainloop_asm): + sub rsp, 48 + mov rcx, rdi + #include "cn2/cnv2_rwz_main_loop.inc" + add rsp, 48 + ret 0 + mov eax, 3735929054 + +ALIGN(64) +FN_PREFIX(cnv2_rwz_double_mainloop_asm): + sub rsp, 48 + mov rcx, rdi + #include "cn2/cnv2_rwz_double_main_loop.inc" + add rsp, 48 + ret 0 + mov eax, 3735929054 diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_soft_aes_template_win.inc b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_soft_aes_template_win.inc new file mode 100644 index 000000000..d6d393a96 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_soft_aes_template_win.inc @@ -0,0 +1,279 @@ +PUBLIC CryptonightR_soft_aes_template_part1 +PUBLIC CryptonightR_soft_aes_template_mainloop +PUBLIC CryptonightR_soft_aes_template_part2 +PUBLIC CryptonightR_soft_aes_template_part3 +PUBLIC CryptonightR_soft_aes_template_end + +ALIGN(64) +CryptonightR_soft_aes_template_part1: + mov QWORD PTR [rsp+8], rcx + push rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 232 + + mov eax, [rcx+96] + mov ebx, [rcx+100] + mov esi, [rcx+104] + mov edx, [rcx+108] + mov [rsp+144], eax + mov [rsp+148], ebx + mov [rsp+152], esi + mov [rsp+156], edx + + mov rax, QWORD PTR [rcx+48] + mov r10, rcx + xor rax, QWORD PTR [rcx+16] + mov r8, QWORD PTR [rcx+32] + xor r8, QWORD PTR [rcx] + mov r9, QWORD PTR [rcx+40] + xor r9, QWORD PTR [rcx+8] + movd xmm4, rax + mov rdx, QWORD PTR [rcx+56] + xor rdx, QWORD PTR [rcx+24] + mov r11, QWORD PTR [rcx+224] + mov rcx, QWORD PTR [rcx+88] + xor rcx, QWORD PTR [r10+72] + mov rax, QWORD PTR [r10+80] + movd xmm0, rdx + xor rax, QWORD PTR [r10+64] + + movaps XMMWORD PTR [rsp+16], xmm6 + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+48], xmm8 + movaps XMMWORD PTR [rsp+64], xmm9 + movaps XMMWORD PTR [rsp+80], xmm10 + movaps XMMWORD PTR [rsp+96], xmm11 + movaps XMMWORD PTR [rsp+112], xmm12 + movaps XMMWORD PTR [rsp+128], xmm13 + + movd xmm5, rax + + mov rax, r8 + punpcklqdq xmm4, xmm0 + and eax, 2097136 + movd xmm10, QWORD PTR [r10+96] + movd xmm0, rcx + mov rcx, QWORD PTR [r10+104] + xorps xmm9, xmm9 + mov QWORD PTR [rsp+328], rax + movd xmm12, r11 + mov QWORD PTR [rsp+320], r9 + punpcklqdq xmm5, xmm0 + movd xmm13, rcx + mov r12d, 524288 + + ALIGN(64) +CryptonightR_soft_aes_template_mainloop: + movd xmm11, r12d + mov r12, QWORD PTR [r10+272] + lea r13, QWORD PTR [rax+r11] + mov esi, DWORD PTR [r13] + movd xmm0, r9 + mov r10d, DWORD PTR [r13+4] + movd xmm7, r8 + mov ebp, DWORD PTR [r13+12] + mov r14d, DWORD PTR [r13+8] + mov rdx, QWORD PTR [rsp+328] + movzx ecx, sil + shr esi, 8 + punpcklqdq xmm7, xmm0 + mov r15d, DWORD PTR [r12+rcx*4] + movzx ecx, r10b + shr r10d, 8 + mov edi, DWORD PTR [r12+rcx*4] + movzx ecx, r14b + shr r14d, 8 + mov ebx, DWORD PTR [r12+rcx*4] + movzx ecx, bpl + shr ebp, 8 + mov r9d, DWORD PTR [r12+rcx*4] + movzx ecx, r10b + shr r10d, 8 + xor r15d, DWORD PTR [r12+rcx*4+1024] + movzx ecx, r14b + shr r14d, 8 + mov eax, r14d + shr eax, 8 + xor edi, DWORD PTR [r12+rcx*4+1024] + add eax, 256 + movzx ecx, bpl + shr ebp, 8 + xor ebx, DWORD PTR [r12+rcx*4+1024] + movzx ecx, sil + shr esi, 8 + xor r9d, DWORD PTR [r12+rcx*4+1024] + add r12, 2048 + movzx ecx, r10b + shr r10d, 8 + add r10d, 256 + mov r11d, DWORD PTR [r12+rax*4] + xor r11d, DWORD PTR [r12+rcx*4] + xor r11d, r9d + movzx ecx, sil + mov r10d, DWORD PTR [r12+r10*4] + shr esi, 8 + add esi, 256 + xor r10d, DWORD PTR [r12+rcx*4] + movzx ecx, bpl + xor r10d, ebx + shr ebp, 8 + movd xmm1, r11d + add ebp, 256 + movd r11, xmm12 + mov r9d, DWORD PTR [r12+rcx*4] + xor r9d, DWORD PTR [r12+rsi*4] + mov eax, DWORD PTR [r12+rbp*4] + xor r9d, edi + movzx ecx, r14b + movd xmm0, r10d + movd xmm2, r9d + xor eax, DWORD PTR [r12+rcx*4] + mov rcx, rdx + xor eax, r15d + punpckldq xmm2, xmm1 + xor rcx, 16 + movd xmm6, eax + mov rax, rdx + punpckldq xmm6, xmm0 + xor rax, 32 + punpckldq xmm6, xmm2 + xor rdx, 48 + movdqu xmm2, XMMWORD PTR [rcx+r11] + pxor xmm6, xmm2 + pxor xmm6, xmm7 + paddq xmm2, xmm4 + movdqu xmm1, XMMWORD PTR [rax+r11] + movdqu xmm0, XMMWORD PTR [rdx+r11] + pxor xmm6, xmm1 + pxor xmm6, xmm0 + paddq xmm0, xmm5 + movdqu XMMWORD PTR [rcx+r11], xmm0 + movdqu XMMWORD PTR [rax+r11], xmm2 + movd rcx, xmm13 + paddq xmm1, xmm7 + movdqu XMMWORD PTR [rdx+r11], xmm1 + movd rdi, xmm6 + mov r10, rdi + and r10d, 2097136 + movdqa xmm0, xmm6 + pxor xmm0, xmm4 + movdqu XMMWORD PTR [r13], xmm0 + + mov ebx, [rsp+144] + mov ebp, [rsp+152] + add ebx, [rsp+148] + add ebp, [rsp+156] + shl rbp, 32 + or rbx, rbp + + xor rbx, QWORD PTR [r10+r11] + lea r14, QWORD PTR [r10+r11] + mov rbp, QWORD PTR [r14+8] + + mov [rsp+160], rbx + mov [rsp+168], rdi + mov [rsp+176], rbp + mov [rsp+184], r10 + mov r10, rsp + + mov ebx, [rsp+144] + mov esi, [rsp+148] + mov edi, [rsp+152] + mov ebp, [rsp+156] + + movd esp, xmm7 + movaps xmm0, xmm7 + psrldq xmm0, 8 + movd r15d, xmm0 + movd eax, xmm4 + movd edx, xmm5 + movaps xmm0, xmm5 + psrldq xmm0, 8 + movd r9d, xmm0 + +CryptonightR_soft_aes_template_part2: + mov rsp, r10 + mov [rsp+144], ebx + mov [rsp+148], esi + mov [rsp+152], edi + mov [rsp+156], ebp + + mov edi, edi + shl rbp, 32 + or rbp, rdi + xor r8, rbp + + mov ebx, ebx + shl rsi, 32 + or rsi, rbx + xor QWORD PTR [rsp+320], rsi + + mov rbx, [rsp+160] + mov rdi, [rsp+168] + mov rbp, [rsp+176] + mov r10, [rsp+184] + + mov r9, r10 + xor r9, 16 + mov rcx, r10 + xor rcx, 32 + xor r10, 48 + mov rax, rbx + mul rdi + movdqu xmm2, XMMWORD PTR [r9+r11] + movdqu xmm1, XMMWORD PTR [rcx+r11] + pxor xmm6, xmm2 + pxor xmm6, xmm1 + paddq xmm1, xmm7 + add r8, rdx + movdqu xmm0, XMMWORD PTR [r10+r11] + pxor xmm6, xmm0 + paddq xmm0, xmm5 + paddq xmm2, xmm4 + movdqu XMMWORD PTR [r9+r11], xmm0 + movdqa xmm5, xmm4 + mov r9, QWORD PTR [rsp+320] + movdqa xmm4, xmm6 + add r9, rax + movdqu XMMWORD PTR [rcx+r11], xmm2 + movdqu XMMWORD PTR [r10+r11], xmm1 + mov r10, QWORD PTR [rsp+304] + movd r12d, xmm11 + mov QWORD PTR [r14], r8 + xor r8, rbx + mov rax, r8 + mov QWORD PTR [r14+8], r9 + and eax, 2097136 + xor r9, rbp + mov QWORD PTR [rsp+320], r9 + mov QWORD PTR [rsp+328], rax + sub r12d, 1 + jne CryptonightR_soft_aes_template_mainloop + +CryptonightR_soft_aes_template_part3: + movaps xmm6, XMMWORD PTR [rsp+16] + movaps xmm7, XMMWORD PTR [rsp+32] + movaps xmm8, XMMWORD PTR [rsp+48] + movaps xmm9, XMMWORD PTR [rsp+64] + movaps xmm10, XMMWORD PTR [rsp+80] + movaps xmm11, XMMWORD PTR [rsp+96] + movaps xmm12, XMMWORD PTR [rsp+112] + movaps xmm13, XMMWORD PTR [rsp+128] + + add rsp, 232 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + pop rbx + ret +CryptonightR_soft_aes_template_end: diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.asm b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.asm index 25b72c3c0..250eca3d0 100644 --- a/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.asm +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template.asm @@ -518,6 +518,8 @@ PUBLIC CryptonightR_instruction_mov256 INCLUDE CryptonightWOW_template_win.inc INCLUDE CryptonightR_template_win.inc +INCLUDE CryptonightWOW_soft_aes_template_win.inc +INCLUDE CryptonightR_soft_aes_template_win.inc CryptonightR_instruction0: imul rbx, rbx diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template_win.inc b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template_win.inc index 2f2d71a25..60ee3441b 100644 --- a/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template_win.inc +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightR_template_win.inc @@ -70,29 +70,30 @@ CryptonightR_template_mainloop: aesenc xmm5, xmm4 - mov r12d, r9d + mov r13d, r9d mov eax, r9d xor r9d, 48 - xor r12d, 16 + xor r13d, 16 xor eax, 32 movdqu xmm0, XMMWORD PTR [r9+r11] movaps xmm3, xmm0 - movdqu xmm2, XMMWORD PTR [r12+r11] + movdqu xmm2, XMMWORD PTR [r13+r11] movdqu xmm1, XMMWORD PTR [rax+r11] pxor xmm0, xmm2 pxor xmm5, xmm1 pxor xmm5, xmm0 + + movd r12, xmm5 + movd r10d, xmm5 + and r10d, 2097136 + paddq xmm3, xmm7 paddq xmm2, xmm6 paddq xmm1, xmm4 - movdqu XMMWORD PTR [r12+r11], xmm3 + movdqu XMMWORD PTR [r13+r11], xmm3 movdqu XMMWORD PTR [rax+r11], xmm2 movdqu XMMWORD PTR [r9+r11], xmm1 - movd r12, xmm5 - movd r10d, xmm5 - and r10d, 2097136 - movdqa xmm0, xmm5 pxor xmm0, xmm6 movdqu XMMWORD PTR [rdx], xmm0 @@ -102,14 +103,16 @@ CryptonightR_template_mainloop: shl rdx, 32 or r13, rdx - xor r13, QWORD PTR [r10+r11] - mov r14, QWORD PTR [r10+r11+8] - movd eax, xmm6 movd edx, xmm7 pextrd r9d, xmm7, 2 + xor r13, QWORD PTR [r10+r11] + mov r14, QWORD PTR [r10+r11+8] + CryptonightR_template_part2: + lea rcx, [r10+r11] + mov eax, edi mov edx, ebp shl rdx, 32 @@ -124,6 +127,8 @@ CryptonightR_template_part2: mov rax, r13 mul r12 + add r15, rax + add rsp, rdx mov r9d, r10d mov r12d, r10d @@ -145,13 +150,10 @@ CryptonightR_template_part2: movdqu XMMWORD PTR [r10+r11], xmm3 movdqa xmm7, xmm6 - add r15, rax - add rsp, rdx - xor r10, 48 - mov QWORD PTR [r10+r11], rsp + mov QWORD PTR [rcx], rsp xor rsp, r13 mov r9d, esp - mov QWORD PTR [r10+r11+8], r15 + mov QWORD PTR [rcx+8], r15 and r9d, 2097136 xor r15, r14 movdqa xmm6, xmm5 diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightWOW_soft_aes_template_win.inc b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightWOW_soft_aes_template_win.inc new file mode 100644 index 000000000..682090367 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/CryptonightWOW_soft_aes_template_win.inc @@ -0,0 +1,266 @@ +PUBLIC CryptonightWOW_soft_aes_template_part1 +PUBLIC CryptonightWOW_soft_aes_template_mainloop +PUBLIC CryptonightWOW_soft_aes_template_part2 +PUBLIC CryptonightWOW_soft_aes_template_part3 +PUBLIC CryptonightWOW_soft_aes_template_end + +ALIGN(64) +CryptonightWOW_soft_aes_template_part1: + mov QWORD PTR [rsp+8], rcx + push rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 232 + + mov eax, [rcx+96] + mov ebx, [rcx+100] + mov esi, [rcx+104] + mov edx, [rcx+108] + mov [rsp+144], eax + mov [rsp+148], ebx + mov [rsp+152], esi + mov [rsp+156], edx + + mov rax, QWORD PTR [rcx+48] + mov r10, rcx + xor rax, QWORD PTR [rcx+16] + mov r8, QWORD PTR [rcx+32] + xor r8, QWORD PTR [rcx] + mov r9, QWORD PTR [rcx+40] + xor r9, QWORD PTR [rcx+8] + movd xmm4, rax + mov rdx, QWORD PTR [rcx+56] + xor rdx, QWORD PTR [rcx+24] + mov r11, QWORD PTR [rcx+224] + mov rcx, QWORD PTR [rcx+88] + xor rcx, QWORD PTR [r10+72] + mov rax, QWORD PTR [r10+80] + movd xmm0, rdx + xor rax, QWORD PTR [r10+64] + + movaps XMMWORD PTR [rsp+16], xmm6 + movaps XMMWORD PTR [rsp+32], xmm7 + movaps XMMWORD PTR [rsp+48], xmm8 + movaps XMMWORD PTR [rsp+64], xmm9 + movaps XMMWORD PTR [rsp+80], xmm10 + movaps XMMWORD PTR [rsp+96], xmm11 + movaps XMMWORD PTR [rsp+112], xmm12 + movaps XMMWORD PTR [rsp+128], xmm13 + + movd xmm5, rax + + mov rax, r8 + punpcklqdq xmm4, xmm0 + and eax, 2097136 + movd xmm10, QWORD PTR [r10+96] + movd xmm0, rcx + mov rcx, QWORD PTR [r10+104] + xorps xmm9, xmm9 + mov QWORD PTR [rsp+328], rax + movd xmm12, r11 + mov QWORD PTR [rsp+320], r9 + punpcklqdq xmm5, xmm0 + movd xmm13, rcx + mov r12d, 524288 + + ALIGN(64) +CryptonightWOW_soft_aes_template_mainloop: + movd xmm11, r12d + mov r12, QWORD PTR [r10+272] + lea r13, QWORD PTR [rax+r11] + mov esi, DWORD PTR [r13] + movd xmm0, r9 + mov r10d, DWORD PTR [r13+4] + movd xmm7, r8 + mov ebp, DWORD PTR [r13+12] + mov r14d, DWORD PTR [r13+8] + mov rdx, QWORD PTR [rsp+328] + movzx ecx, sil + shr esi, 8 + punpcklqdq xmm7, xmm0 + mov r15d, DWORD PTR [r12+rcx*4] + movzx ecx, r10b + shr r10d, 8 + mov edi, DWORD PTR [r12+rcx*4] + movzx ecx, r14b + shr r14d, 8 + mov ebx, DWORD PTR [r12+rcx*4] + movzx ecx, bpl + shr ebp, 8 + mov r9d, DWORD PTR [r12+rcx*4] + movzx ecx, r10b + shr r10d, 8 + xor r15d, DWORD PTR [r12+rcx*4+1024] + movzx ecx, r14b + shr r14d, 8 + mov eax, r14d + shr eax, 8 + xor edi, DWORD PTR [r12+rcx*4+1024] + add eax, 256 + movzx ecx, bpl + shr ebp, 8 + xor ebx, DWORD PTR [r12+rcx*4+1024] + movzx ecx, sil + shr esi, 8 + xor r9d, DWORD PTR [r12+rcx*4+1024] + add r12, 2048 + movzx ecx, r10b + shr r10d, 8 + add r10d, 256 + mov r11d, DWORD PTR [r12+rax*4] + xor r11d, DWORD PTR [r12+rcx*4] + xor r11d, r9d + movzx ecx, sil + mov r10d, DWORD PTR [r12+r10*4] + shr esi, 8 + add esi, 256 + xor r10d, DWORD PTR [r12+rcx*4] + movzx ecx, bpl + xor r10d, ebx + shr ebp, 8 + movd xmm1, r11d + add ebp, 256 + movd r11, xmm12 + mov r9d, DWORD PTR [r12+rcx*4] + xor r9d, DWORD PTR [r12+rsi*4] + mov eax, DWORD PTR [r12+rbp*4] + xor r9d, edi + movzx ecx, r14b + movd xmm0, r10d + movd xmm2, r9d + xor eax, DWORD PTR [r12+rcx*4] + mov rcx, rdx + xor eax, r15d + punpckldq xmm2, xmm1 + xor rcx, 16 + movd xmm6, eax + mov rax, rdx + punpckldq xmm6, xmm0 + xor rax, 32 + punpckldq xmm6, xmm2 + xor rdx, 48 + movdqu xmm2, XMMWORD PTR [rcx+r11] + pxor xmm6, xmm7 + paddq xmm2, xmm4 + movdqu xmm1, XMMWORD PTR [rax+r11] + movdqu xmm0, XMMWORD PTR [rdx+r11] + paddq xmm0, xmm5 + movdqu XMMWORD PTR [rcx+r11], xmm0 + movdqu XMMWORD PTR [rax+r11], xmm2 + movd rcx, xmm13 + paddq xmm1, xmm7 + movdqu XMMWORD PTR [rdx+r11], xmm1 + movd rdi, xmm6 + mov r10, rdi + and r10d, 2097136 + movdqa xmm0, xmm6 + pxor xmm0, xmm4 + movdqu XMMWORD PTR [r13], xmm0 + + mov ebx, [rsp+144] + mov ebp, [rsp+152] + add ebx, [rsp+148] + add ebp, [rsp+156] + shl rbp, 32 + or rbx, rbp + + xor rbx, QWORD PTR [r10+r11] + lea r14, QWORD PTR [r10+r11] + mov rbp, QWORD PTR [r14+8] + + mov [rsp+160], rbx + mov [rsp+168], rdi + mov [rsp+176], rbp + mov [rsp+184], r10 + mov r10, rsp + + mov ebx, [rsp+144] + mov esi, [rsp+148] + mov edi, [rsp+152] + mov ebp, [rsp+156] + + movd esp, xmm7 + movaps xmm0, xmm7 + psrldq xmm0, 8 + movd r15d, xmm0 + movd eax, xmm4 + movd edx, xmm5 + +CryptonightWOW_soft_aes_template_part2: + mov rsp, r10 + mov [rsp+144], ebx + mov [rsp+148], esi + mov [rsp+152], edi + mov [rsp+156], ebp + + mov rbx, [rsp+160] + mov rdi, [rsp+168] + mov rbp, [rsp+176] + mov r10, [rsp+184] + + mov r9, r10 + xor r9, 16 + mov rcx, r10 + xor rcx, 32 + xor r10, 48 + mov rax, rbx + mul rdi + movdqu xmm2, XMMWORD PTR [r9+r11] + movdqu xmm1, XMMWORD PTR [rcx+r11] + paddq xmm1, xmm7 + movd xmm0, rax + movd xmm3, rdx + xor rax, QWORD PTR [r11+rcx+8] + xor rdx, QWORD PTR [rcx+r11] + punpcklqdq xmm3, xmm0 + add r8, rdx + movdqu xmm0, XMMWORD PTR [r10+r11] + pxor xmm2, xmm3 + paddq xmm0, xmm5 + paddq xmm2, xmm4 + movdqu XMMWORD PTR [r9+r11], xmm0 + movdqa xmm5, xmm4 + mov r9, QWORD PTR [rsp+320] + movdqa xmm4, xmm6 + add r9, rax + movdqu XMMWORD PTR [rcx+r11], xmm2 + movdqu XMMWORD PTR [r10+r11], xmm1 + mov r10, QWORD PTR [rsp+304] + movd r12d, xmm11 + mov QWORD PTR [r14], r8 + xor r8, rbx + mov rax, r8 + mov QWORD PTR [r14+8], r9 + and eax, 2097136 + xor r9, rbp + mov QWORD PTR [rsp+320], r9 + mov QWORD PTR [rsp+328], rax + sub r12d, 1 + jne CryptonightWOW_soft_aes_template_mainloop + +CryptonightWOW_soft_aes_template_part3: + movaps xmm6, XMMWORD PTR [rsp+16] + movaps xmm7, XMMWORD PTR [rsp+32] + movaps xmm8, XMMWORD PTR [rsp+48] + movaps xmm9, XMMWORD PTR [rsp+64] + movaps xmm10, XMMWORD PTR [rsp+80] + movaps xmm11, XMMWORD PTR [rsp+96] + movaps xmm12, XMMWORD PTR [rsp+112] + movaps xmm13, XMMWORD PTR [rsp+128] + + add rsp, 232 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + pop rbx + ret +CryptonightWOW_soft_aes_template_end: diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_rwz_double_main_loop.inc b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_rwz_double_main_loop.inc new file mode 100644 index 000000000..69ca8793c --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_rwz_double_main_loop.inc @@ -0,0 +1,410 @@ + mov rax, rsp + push rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 184 + + stmxcsr DWORD PTR [rsp+272] + mov DWORD PTR [rsp+276], 24448 + ldmxcsr DWORD PTR [rsp+276] + + mov r13, QWORD PTR [rcx+224] + mov r9, rdx + mov r10, QWORD PTR [rcx+32] + mov r8, rcx + xor r10, QWORD PTR [rcx] + mov r14d, 393216 + mov r11, QWORD PTR [rcx+40] + xor r11, QWORD PTR [rcx+8] + mov rsi, QWORD PTR [rdx+224] + mov rdx, QWORD PTR [rcx+56] + xor rdx, QWORD PTR [rcx+24] + mov rdi, QWORD PTR [r9+32] + xor rdi, QWORD PTR [r9] + mov rbp, QWORD PTR [r9+40] + xor rbp, QWORD PTR [r9+8] + movd xmm0, rdx + movaps XMMWORD PTR [rax-88], xmm6 + movaps XMMWORD PTR [rax-104], xmm7 + movaps XMMWORD PTR [rax-120], xmm8 + movaps XMMWORD PTR [rsp+112], xmm9 + movaps XMMWORD PTR [rsp+96], xmm10 + movaps XMMWORD PTR [rsp+80], xmm11 + movaps XMMWORD PTR [rsp+64], xmm12 + movaps XMMWORD PTR [rsp+48], xmm13 + movaps XMMWORD PTR [rsp+32], xmm14 + movaps XMMWORD PTR [rsp+16], xmm15 + mov rdx, r10 + movd xmm4, QWORD PTR [r8+96] + and edx, 2097136 + mov rax, QWORD PTR [rcx+48] + xorps xmm13, xmm13 + xor rax, QWORD PTR [rcx+16] + mov rcx, QWORD PTR [rcx+88] + xor rcx, QWORD PTR [r8+72] + movd xmm5, QWORD PTR [r8+104] + movd xmm7, rax + + mov eax, 1 + shl rax, 52 + movd xmm14, rax + punpcklqdq xmm14, xmm14 + + mov eax, 1023 + shl rax, 52 + movd xmm12, rax + punpcklqdq xmm12, xmm12 + + mov rax, QWORD PTR [r8+80] + xor rax, QWORD PTR [r8+64] + punpcklqdq xmm7, xmm0 + movd xmm0, rcx + mov rcx, QWORD PTR [r9+56] + xor rcx, QWORD PTR [r9+24] + movd xmm3, rax + mov rax, QWORD PTR [r9+48] + xor rax, QWORD PTR [r9+16] + punpcklqdq xmm3, xmm0 + movd xmm0, rcx + mov QWORD PTR [rsp], r13 + mov rcx, QWORD PTR [r9+88] + xor rcx, QWORD PTR [r9+72] + movd xmm6, rax + mov rax, QWORD PTR [r9+80] + xor rax, QWORD PTR [r9+64] + punpcklqdq xmm6, xmm0 + movd xmm0, rcx + mov QWORD PTR [rsp+256], r10 + mov rcx, rdi + mov QWORD PTR [rsp+264], r11 + movd xmm8, rax + and ecx, 2097136 + punpcklqdq xmm8, xmm0 + movd xmm0, QWORD PTR [r9+96] + punpcklqdq xmm4, xmm0 + movd xmm0, QWORD PTR [r9+104] + lea r8, QWORD PTR [rcx+rsi] + movdqu xmm11, XMMWORD PTR [r8] + punpcklqdq xmm5, xmm0 + lea r9, QWORD PTR [rdx+r13] + movdqu xmm15, XMMWORD PTR [r9] + + ALIGN(64) +rwz_main_loop_double: + movdqu xmm9, xmm15 + mov eax, edx + mov ebx, edx + xor eax, 16 + xor ebx, 32 + xor edx, 48 + + movd xmm0, r11 + movd xmm2, r10 + punpcklqdq xmm2, xmm0 + aesenc xmm9, xmm2 + + movdqu xmm0, XMMWORD PTR [rdx+r13] + movdqu xmm1, XMMWORD PTR [rbx+r13] + paddq xmm0, xmm7 + paddq xmm1, xmm2 + movdqu XMMWORD PTR [rbx+r13], xmm0 + movdqu xmm0, XMMWORD PTR [rax+r13] + movdqu XMMWORD PTR [rdx+r13], xmm1 + paddq xmm0, xmm3 + movdqu XMMWORD PTR [rax+r13], xmm0 + + movd r11, xmm9 + mov edx, r11d + and edx, 2097136 + movdqa xmm0, xmm9 + pxor xmm0, xmm7 + movdqu XMMWORD PTR [r9], xmm0 + + lea rbx, QWORD PTR [rdx+r13] + mov r10, QWORD PTR [rdx+r13] + + movdqu xmm10, xmm11 + movd xmm0, rbp + movd xmm11, rdi + punpcklqdq xmm11, xmm0 + aesenc xmm10, xmm11 + + mov eax, ecx + mov r12d, ecx + xor eax, 16 + xor r12d, 32 + xor ecx, 48 + + movdqu xmm0, XMMWORD PTR [rcx+rsi] + paddq xmm0, xmm6 + movdqu xmm1, XMMWORD PTR [r12+rsi] + movdqu XMMWORD PTR [r12+rsi], xmm0 + paddq xmm1, xmm11 + movdqu xmm0, XMMWORD PTR [rax+rsi] + movdqu XMMWORD PTR [rcx+rsi], xmm1 + paddq xmm0, xmm8 + movdqu XMMWORD PTR [rax+rsi], xmm0 + + movd rcx, xmm10 + and ecx, 2097136 + + movdqa xmm0, xmm10 + pxor xmm0, xmm6 + movdqu XMMWORD PTR [r8], xmm0 + mov r12, QWORD PTR [rcx+rsi] + + mov r9, QWORD PTR [rbx+8] + + xor edx, 16 + mov r8d, edx + mov r15d, edx + + movd rdx, xmm5 + shl rdx, 32 + movd rax, xmm4 + xor rdx, rax + xor r10, rdx + mov rax, r10 + mul r11 + mov r11d, r8d + xor r11d, 48 + movd xmm0, rdx + xor rdx, [r11+r13] + movd xmm1, rax + xor rax, [r11+r13+8] + punpcklqdq xmm0, xmm1 + + pxor xmm0, XMMWORD PTR [r8+r13] + movdqu xmm1, XMMWORD PTR [r11+r13] + paddq xmm0, xmm3 + paddq xmm1, xmm2 + movdqu XMMWORD PTR [r8+r13], xmm0 + xor r8d, 32 + movdqu xmm0, XMMWORD PTR [r8+r13] + movdqu XMMWORD PTR [r8+r13], xmm1 + paddq xmm0, xmm7 + movdqu XMMWORD PTR [r11+r13], xmm0 + + mov r11, QWORD PTR [rsp+256] + add r11, rdx + mov rdx, QWORD PTR [rsp+264] + add rdx, rax + mov QWORD PTR [rbx], r11 + xor r11, r10 + mov QWORD PTR [rbx+8], rdx + xor rdx, r9 + mov QWORD PTR [rsp+256], r11 + and r11d, 2097136 + mov QWORD PTR [rsp+264], rdx + mov QWORD PTR [rsp+8], r11 + lea r15, QWORD PTR [r11+r13] + movdqu xmm15, XMMWORD PTR [r11+r13] + lea r13, QWORD PTR [rsi+rcx] + movdqa xmm0, xmm5 + psrldq xmm0, 8 + movaps xmm2, xmm13 + movd r10, xmm0 + psllq xmm5, 1 + shl r10, 32 + movdqa xmm0, xmm9 + psrldq xmm0, 8 + movdqa xmm1, xmm10 + movd r11, xmm0 + psrldq xmm1, 8 + movd r8, xmm1 + psrldq xmm4, 8 + movaps xmm0, xmm13 + movd rax, xmm4 + xor r10, rax + movaps xmm1, xmm13 + xor r10, r12 + lea rax, QWORD PTR [r11+1] + shr rax, 1 + movdqa xmm3, xmm9 + punpcklqdq xmm3, xmm10 + paddq xmm5, xmm3 + movd rdx, xmm5 + psrldq xmm5, 8 + cvtsi2sd xmm2, rax + or edx, -2147483647 + lea rax, QWORD PTR [r8+1] + shr rax, 1 + movd r9, xmm5 + cvtsi2sd xmm0, rax + or r9d, -2147483647 + cvtsi2sd xmm1, rdx + unpcklpd xmm2, xmm0 + movaps xmm0, xmm13 + cvtsi2sd xmm0, r9 + unpcklpd xmm1, xmm0 + divpd xmm2, xmm1 + paddq xmm2, xmm14 + cvttsd2si rax, xmm2 + psrldq xmm2, 8 + mov rbx, rax + imul rax, rdx + sub r11, rax + js rwz_div_fix_1 +rwz_div_fix_1_ret: + + cvttsd2si rdx, xmm2 + mov rax, rdx + imul rax, r9 + movd xmm2, r11d + movd xmm4, ebx + sub r8, rax + js rwz_div_fix_2 +rwz_div_fix_2_ret: + + movd xmm1, r8d + movd xmm0, edx + punpckldq xmm2, xmm1 + punpckldq xmm4, xmm0 + punpckldq xmm4, xmm2 + paddq xmm3, xmm4 + movdqa xmm0, xmm3 + psrlq xmm0, 12 + paddq xmm0, xmm12 + sqrtpd xmm1, xmm0 + movd r9, xmm1 + movdqa xmm5, xmm1 + psrlq xmm5, 19 + test r9, 524287 + je rwz_sqrt_fix_1 +rwz_sqrt_fix_1_ret: + + movd r9, xmm10 + psrldq xmm1, 8 + movd r8, xmm1 + test r8, 524287 + je rwz_sqrt_fix_2 +rwz_sqrt_fix_2_ret: + + mov r12d, ecx + mov r8d, ecx + xor r12d, 16 + xor r8d, 32 + xor ecx, 48 + mov rax, r10 + mul r9 + movd xmm0, rax + movd xmm3, rdx + punpcklqdq xmm3, xmm0 + + movdqu xmm0, XMMWORD PTR [r12+rsi] + pxor xmm0, xmm3 + movdqu xmm1, XMMWORD PTR [r8+rsi] + xor rdx, [r8+rsi] + xor rax, [r8+rsi+8] + movdqu xmm3, XMMWORD PTR [rcx+rsi] + paddq xmm3, xmm6 + paddq xmm1, xmm11 + paddq xmm0, xmm8 + movdqu XMMWORD PTR [r8+rsi], xmm3 + movdqu XMMWORD PTR [rcx+rsi], xmm1 + movdqu XMMWORD PTR [r12+rsi], xmm0 + + add rdi, rdx + mov QWORD PTR [r13], rdi + xor rdi, r10 + mov ecx, edi + and ecx, 2097136 + lea r8, QWORD PTR [rcx+rsi] + + mov rdx, QWORD PTR [r13+8] + add rbp, rax + mov QWORD PTR [r13+8], rbp + movdqu xmm11, XMMWORD PTR [rcx+rsi] + xor rbp, rdx + mov r13, QWORD PTR [rsp] + movdqa xmm3, xmm7 + mov rdx, QWORD PTR [rsp+8] + movdqa xmm8, xmm6 + mov r10, QWORD PTR [rsp+256] + movdqa xmm7, xmm9 + mov r11, QWORD PTR [rsp+264] + movdqa xmm6, xmm10 + mov r9, r15 + dec r14d + jne rwz_main_loop_double + + ldmxcsr DWORD PTR [rsp+272] + movaps xmm13, XMMWORD PTR [rsp+48] + lea r11, QWORD PTR [rsp+184] + movaps xmm6, XMMWORD PTR [r11-24] + movaps xmm7, XMMWORD PTR [r11-40] + movaps xmm8, XMMWORD PTR [r11-56] + movaps xmm9, XMMWORD PTR [r11-72] + movaps xmm10, XMMWORD PTR [r11-88] + movaps xmm11, XMMWORD PTR [r11-104] + movaps xmm12, XMMWORD PTR [r11-120] + movaps xmm14, XMMWORD PTR [rsp+32] + movaps xmm15, XMMWORD PTR [rsp+16] + mov rsp, r11 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + pop rbx + jmp rwz_cnv2_double_mainloop_asm_endp + +rwz_div_fix_1: + dec rbx + add r11, rdx + jmp rwz_div_fix_1_ret + +rwz_div_fix_2: + dec rdx + add r8, r9 + jmp rwz_div_fix_2_ret + +rwz_sqrt_fix_1: + movd r8, xmm3 + movdqa xmm0, xmm5 + psrldq xmm0, 8 + dec r9 + mov r11d, -1022 + shl r11, 32 + mov rax, r9 + shr r9, 19 + shr rax, 20 + mov rdx, r9 + sub rdx, rax + lea rdx, [rdx+r11+1] + add rax, r11 + imul rdx, rax + sub rdx, r8 + adc r9, 0 + movd xmm5, r9 + punpcklqdq xmm5, xmm0 + jmp rwz_sqrt_fix_1_ret + +rwz_sqrt_fix_2: + psrldq xmm3, 8 + movd r11, xmm3 + dec r8 + mov ebx, -1022 + shl rbx, 32 + mov rax, r8 + shr r8, 19 + shr rax, 20 + mov rdx, r8 + sub rdx, rax + lea rdx, [rdx+rbx+1] + add rax, rbx + imul rdx, rax + sub rdx, r11 + adc r8, 0 + movd xmm0, r8 + punpcklqdq xmm5, xmm0 + jmp rwz_sqrt_fix_2_ret + +rwz_cnv2_double_mainloop_asm_endp: diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_rwz_main_loop.inc b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_rwz_main_loop.inc new file mode 100644 index 000000000..993177305 --- /dev/null +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn2/cnv2_rwz_main_loop.inc @@ -0,0 +1,186 @@ + mov QWORD PTR [rsp+24], rbx + push rbp + push rsi + push rdi + push r12 + push r13 + push r14 + push r15 + sub rsp, 80 + + stmxcsr DWORD PTR [rsp] + mov DWORD PTR [rsp+4], 24448 + ldmxcsr DWORD PTR [rsp+4] + + mov rax, QWORD PTR [rcx+48] + mov r9, rcx + xor rax, QWORD PTR [rcx+16] + mov esi, 393216 + mov r8, QWORD PTR [rcx+32] + mov r13d, -2147483647 + xor r8, QWORD PTR [rcx] + mov r11, QWORD PTR [rcx+40] + mov r10, r8 + mov rdx, QWORD PTR [rcx+56] + movd xmm4, rax + xor rdx, QWORD PTR [rcx+24] + xor r11, QWORD PTR [rcx+8] + mov rbx, QWORD PTR [rcx+224] + mov rax, QWORD PTR [r9+80] + xor rax, QWORD PTR [r9+64] + movd xmm0, rdx + mov rcx, QWORD PTR [rcx+88] + xor rcx, QWORD PTR [r9+72] + movd xmm3, QWORD PTR [r9+104] + movaps XMMWORD PTR [rsp+64], xmm6 + movaps XMMWORD PTR [rsp+48], xmm7 + movaps XMMWORD PTR [rsp+32], xmm8 + and r10d, 2097136 + movd xmm5, rax + + xor eax, eax + mov QWORD PTR [rsp+16], rax + + mov ax, 1023 + shl rax, 52 + movd xmm8, rax + mov r15, QWORD PTR [r9+96] + punpcklqdq xmm4, xmm0 + movd xmm0, rcx + punpcklqdq xmm5, xmm0 + movdqu xmm6, XMMWORD PTR [r10+rbx] + + ALIGN(64) +rwz_main_loop: + lea rdx, QWORD PTR [r10+rbx] + mov ecx, r10d + mov eax, r10d + mov rdi, r15 + xor ecx, 16 + xor eax, 32 + xor r10d, 48 + movd xmm0, r11 + movd xmm7, r8 + punpcklqdq xmm7, xmm0 + aesenc xmm6, xmm7 + movd rbp, xmm6 + mov r9, rbp + and r9d, 2097136 + movdqu xmm0, XMMWORD PTR [rcx+rbx] + movdqu xmm1, XMMWORD PTR [rax+rbx] + movdqu xmm2, XMMWORD PTR [r10+rbx] + paddq xmm0, xmm5 + paddq xmm1, xmm7 + paddq xmm2, xmm4 + movdqu XMMWORD PTR [rcx+rbx], xmm0 + movdqu XMMWORD PTR [rax+rbx], xmm2 + movdqu XMMWORD PTR [r10+rbx], xmm1 + mov r10, r9 + xor r10d, 32 + movd rcx, xmm3 + mov rax, rcx + shl rax, 32 + xor rdi, rax + movdqa xmm0, xmm6 + pxor xmm0, xmm4 + movdqu XMMWORD PTR [rdx], xmm0 + xor rdi, QWORD PTR [r9+rbx] + lea r14, QWORD PTR [r9+rbx] + mov r12, QWORD PTR [r14+8] + xor edx, edx + lea r9d, DWORD PTR [ecx+ecx] + add r9d, ebp + movdqa xmm0, xmm6 + psrldq xmm0, 8 + or r9d, r13d + movd rax, xmm0 + div r9 + xorps xmm3, xmm3 + mov eax, eax + shl rdx, 32 + add rdx, rax + lea r9, QWORD PTR [rdx+rbp] + mov r15, rdx + mov rax, r9 + shr rax, 12 + movd xmm0, rax + paddq xmm0, xmm8 + sqrtsd xmm3, xmm0 + psubq xmm3, XMMWORD PTR [rsp+16] + movd rdx, xmm3 + test edx, 524287 + je rwz_sqrt_fixup + psrlq xmm3, 19 +rwz_sqrt_fixup_ret: + + mov ecx, r10d + mov rax, rdi + mul rbp + movd xmm2, rdx + xor rdx, [rcx+rbx] + add r8, rdx + mov QWORD PTR [r14], r8 + xor r8, rdi + mov edi, r8d + and edi, 2097136 + movd xmm0, rax + xor rax, [rcx+rbx+8] + add r11, rax + mov QWORD PTR [r14+8], r11 + punpcklqdq xmm2, xmm0 + + mov r9d, r10d + xor r9d, 48 + xor r10d, 16 + pxor xmm2, XMMWORD PTR [r9+rbx] + movdqu xmm0, XMMWORD PTR [r10+rbx] + paddq xmm0, xmm4 + movdqu xmm1, XMMWORD PTR [rcx+rbx] + paddq xmm2, xmm5 + paddq xmm1, xmm7 + movdqa xmm5, xmm4 + movdqu XMMWORD PTR [r9+rbx], xmm2 + movdqa xmm4, xmm6 + movdqu XMMWORD PTR [rcx+rbx], xmm0 + movdqu XMMWORD PTR [r10+rbx], xmm1 + movdqu xmm6, [rdi+rbx] + mov r10d, edi + xor r11, r12 + dec rsi + jne rwz_main_loop + + ldmxcsr DWORD PTR [rsp] + mov rbx, QWORD PTR [rsp+160] + movaps xmm6, XMMWORD PTR [rsp+64] + movaps xmm7, XMMWORD PTR [rsp+48] + movaps xmm8, XMMWORD PTR [rsp+32] + add rsp, 80 + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop rsi + pop rbp + jmp cnv2_rwz_main_loop_endp + +rwz_sqrt_fixup: + dec rdx + mov r13d, -1022 + shl r13, 32 + mov rax, rdx + shr rdx, 19 + shr rax, 20 + mov rcx, rdx + sub rcx, rax + add rax, r13 + not r13 + sub rcx, r13 + mov r13d, -2147483647 + imul rcx, rax + sub rcx, r9 + adc rdx, 0 + movd xmm3, rdx + jmp rwz_sqrt_fixup_ret + +cnv2_rwz_main_loop_endp: diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.S b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.S index 1200c4dfe..63c3a8ba6 100644 --- a/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.S +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.S @@ -5,6 +5,8 @@ .global cnv2_mainloop_ryzen_asm .global cnv2_mainloop_bulldozer_asm .global cnv2_double_mainloop_sandybridge_asm +.global cnv2_rwz_mainloop_asm +.global cnv2_rwz_double_mainloop_asm ALIGN(64) cnv2_mainloop_ivybridge_asm: @@ -29,3 +31,15 @@ cnv2_double_mainloop_sandybridge_asm: #include "../cn2/cnv2_double_main_loop_sandybridge.inc" ret 0 mov eax, 3735929054 + +ALIGN(64) +cnv2_rwz_mainloop_asm: + #include "cn2/cnv2_rwz_main_loop.inc" + ret 0 + mov eax, 3735929054 + +ALIGN(64) +cnv2_rwz_double_mainloop_asm: + #include "cn2/cnv2_rwz_double_main_loop.inc" + ret 0 + mov eax, 3735929054 diff --git a/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.asm b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.asm index 846b860c8..57246cf5c 100644 --- a/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.asm +++ b/src/Native/libcryptonight/xmrig/crypto/asm/win64/cn_main_loop.asm @@ -3,6 +3,8 @@ PUBLIC cnv2_mainloop_ivybridge_asm PUBLIC cnv2_mainloop_ryzen_asm PUBLIC cnv2_mainloop_bulldozer_asm PUBLIC cnv2_double_mainloop_sandybridge_asm +PUBLIC cnv2_rwz_mainloop_asm +PUBLIC cnv2_rwz_double_mainloop_asm ALIGN 64 cnv2_mainloop_ivybridge_asm PROC @@ -32,5 +34,19 @@ cnv2_double_mainloop_sandybridge_asm PROC mov eax, 3735929054 cnv2_double_mainloop_sandybridge_asm ENDP +ALIGN(64) +cnv2_rwz_mainloop_asm PROC + INCLUDE cn2/cnv2_rwz_main_loop.inc + ret 0 + mov eax, 3735929054 +cnv2_rwz_mainloop_asm ENDP + +ALIGN(64) +cnv2_rwz_double_mainloop_asm PROC + INCLUDE cn2/cnv2_rwz_double_main_loop.inc + ret 0 + mov eax, 3735929054 +cnv2_rwz_double_mainloop_asm ENDP + _TEXT_CNV2_MAINLOOP ENDS END diff --git a/src/Native/libcryptonight/xmrig/crypto/cn_gpu_arm.cpp b/src/Native/libcryptonight/xmrig/crypto/cn_gpu_arm.cpp index b463dd2ec..2ac9ff1e3 100644 --- a/src/Native/libcryptonight/xmrig/crypto/cn_gpu_arm.cpp +++ b/src/Native/libcryptonight/xmrig/crypto/cn_gpu_arm.cpp @@ -29,6 +29,14 @@ #include "crypto/CryptoNight_constants.h" +#if !defined(__ARM_64BIT_STATE) +float32x4_t vdivq_f32(const float32x4_t a, const float32x4_t b) { + const float32x4_t inv = vrecpeq_f32(b); + return vmulq_f32(a, vmulq_f32(vrecpsq_f32(b, inv), inv)); +} +#endif + + inline void vandq_f32(float32x4_t &v, uint32_t v2) { uint32x4_t vc = vdupq_n_u32(v2); diff --git a/src/Native/libcryptonight/xmrig/extra.cpp b/src/Native/libcryptonight/xmrig/extra.cpp index 8a6636031..50faeba45 100644 --- a/src/Native/libcryptonight/xmrig/extra.cpp +++ b/src/Native/libcryptonight/xmrig/extra.cpp @@ -80,6 +80,16 @@ xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_ryzen_asm xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_bulldozer_asm = nullptr; xmrig::CpuThread::cn_mainloop_double_fun cn_trtl_double_mainloop_sandybridge_asm = nullptr; +xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_ivybridge_asm = nullptr; +xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_ryzen_asm = nullptr; +xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_bulldozer_asm = nullptr; +xmrig::CpuThread::cn_mainloop_double_fun cn_zls_double_mainloop_sandybridge_asm = nullptr; + +xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_ivybridge_asm = nullptr; +xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_ryzen_asm = nullptr; +xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_bulldozer_asm = nullptr; +xmrig::CpuThread::cn_mainloop_double_fun cn_double_double_mainloop_sandybridge_asm = nullptr; + void xmrig::CpuThread::patchAsmVariants() { const int allocation_size = 65536; @@ -95,15 +105,35 @@ void xmrig::CpuThread::patchAsmVariants() cn_trtl_mainloop_bulldozer_asm = reinterpret_cast (base + 0x6000); cn_trtl_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0x7000); - patchCode(cn_half_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_half_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_half_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_half_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); - - patchCode(cn_trtl_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); - patchCode(cn_trtl_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); - patchCode(cn_trtl_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); - patchCode(cn_trtl_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); + cn_zls_mainloop_ivybridge_asm = reinterpret_cast (base + 0x8000); + cn_zls_mainloop_ryzen_asm = reinterpret_cast (base + 0x9000); + cn_zls_mainloop_bulldozer_asm = reinterpret_cast (base + 0xA000); + cn_zls_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0xB000); + + cn_double_mainloop_ivybridge_asm = reinterpret_cast (base + 0xC000); + cn_double_mainloop_ryzen_asm = reinterpret_cast (base + 0xD000); + cn_double_mainloop_bulldozer_asm = reinterpret_cast (base + 0xE000); + cn_double_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0xF000); + + patchCode(cn_half_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); + patchCode(cn_half_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); + patchCode(cn_half_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); + patchCode(cn_half_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); + + patchCode(cn_trtl_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); + patchCode(cn_trtl_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); + patchCode(cn_trtl_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); + patchCode(cn_trtl_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); + + patchCode(cn_zls_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_ZLS_ITER, xmrig::CRYPTONIGHT_MASK); + patchCode(cn_zls_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_ZLS_ITER, xmrig::CRYPTONIGHT_MASK); + patchCode(cn_zls_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_ZLS_ITER, xmrig::CRYPTONIGHT_MASK); + patchCode(cn_zls_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_ZLS_ITER, xmrig::CRYPTONIGHT_MASK); + + patchCode(cn_double_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_DOUBLE_ITER, xmrig::CRYPTONIGHT_MASK); + patchCode(cn_double_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_DOUBLE_ITER, xmrig::CRYPTONIGHT_MASK); + patchCode(cn_double_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_DOUBLE_ITER, xmrig::CRYPTONIGHT_MASK); + patchCode(cn_double_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_DOUBLE_ITER, xmrig::CRYPTONIGHT_MASK); Mem::protectExecutableMemory(base, allocation_size); Mem::flushInstructionCache(base, allocation_size); From eb397921727aafc1012ada8b474ed0a47c3a68e1 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Thu, 4 Apr 2019 13:04:24 +0200 Subject: [PATCH 105/178] Fix appveyor builds --- appveyor.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index ca6ec2d96..4edf88310 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -21,13 +21,13 @@ build_script: - sh: sudo apt-get update -y && sudo apt-get -y install cmake build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 - # Publish - cd Miningcore - - dotnet publish -c Release --framework netcoreapp2.1 + - dotnet publish -c Release --framework netcoreapp2.2 - # Publish Artifacts - - sh: (cd bin/Release/netcoreapp2.1 && mkdir miningcore && cp -r publish/* miningcore && tar cf miningcore-linux-ubuntu-x64.tar.gz miningcore && appveyor PushArtifact miningcore-linux-ubuntu-x64.tar.gz) - - cmd: cd bin\Release\netcoreapp2.1 && mkdir miningcore && xcopy publish\* miningcore /S && 7z a miningcore-win-x64.zip miningcore && appveyor PushArtifact miningcore-win-x64.zip && cd ..\..\.. + - sh: (cd bin/Release/netcoreapp2.2 && mkdir miningcore && cp -r publish/* miningcore && tar cf miningcore-linux-ubuntu-x64.tar.gz miningcore && appveyor PushArtifact miningcore-linux-ubuntu-x64.tar.gz) + - cmd: cd bin\Release\netcoreapp2.2 && mkdir miningcore && xcopy publish\* miningcore /S && 7z a miningcore-win-x64.zip miningcore && appveyor PushArtifact miningcore-win-x64.zip && cd ..\..\.. - # Build Tests - cd ../Miningcore.Tests - - dotnet build -c Release --framework netcoreapp2.1 + - dotnet build -c Release --framework netcoreapp2.2 #---------------------------------# # tests configuration # From 98350f147bb85792d04287d3327ae02af321862b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 4 Apr 2019 13:11:17 +0200 Subject: [PATCH 106/178] Bump NLog from 4.5.11 to 4.6.1 in /src/Miningcore (#593) Bumps [NLog](https://github.com/NLog/NLog) from 4.5.11 to 4.6.1. - [Release notes](https://github.com/NLog/NLog/releases) - [Changelog](https://github.com/NLog/NLog/blob/v4.6.1/CHANGELOG.md) - [Commits](https://github.com/NLog/NLog/compare/v4.5.11...v4.6.1) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index d4ac16f13..6da0536b8 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -66,7 +66,7 @@ - + From 501f2c188dbbad72cbc6074765a2bfb3a592af9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 4 Apr 2019 13:12:04 +0200 Subject: [PATCH 107/178] Bump prometheus-net from 3.0.3 to 3.1.0 in /src/Miningcore (#592) Bumps [prometheus-net](https://github.com/prometheus-net/prometheus-net) from 3.0.3 to 3.1.0. - [Release notes](https://github.com/prometheus-net/prometheus-net/releases) - [Changelog](https://github.com/prometheus-net/prometheus-net/blob/master/History) - [Commits](https://github.com/prometheus-net/prometheus-net/compare/v3.0.3...v3.1.0) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 6da0536b8..be055c9cd 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -70,7 +70,7 @@ - + From 8a5625a91caf3e1150aa7a3a6427a0557c5d616e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 4 Apr 2019 13:12:35 +0200 Subject: [PATCH 108/178] Bump NBitcoin from 4.1.1.82 to 4.1.1.96 in /src/Miningcore (#591) Bumps [NBitcoin](https://github.com/MetacoSA/NBitcoin) from 4.1.1.82 to 4.1.1.96. - [Release notes](https://github.com/MetacoSA/NBitcoin/releases) - [Commits](https://github.com/MetacoSA/NBitcoin/compare/v4.1.1.82...v4.1.1.96) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index be055c9cd..7970bb5b4 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -63,7 +63,7 @@ - + From 990f58f40e36fd3deab4c27a0edaf256b7ae260c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 4 Apr 2019 13:12:49 +0200 Subject: [PATCH 109/178] Bump FluentValidation from 8.1.3 to 8.2.0 in /src/Miningcore (#590) Bumps [FluentValidation](https://github.com/JeremySkinner/fluentvalidation) from 8.1.3 to 8.2.0. - [Release notes](https://github.com/JeremySkinner/fluentvalidation/releases) - [Changelog](https://github.com/JeremySkinner/FluentValidation/blob/master/Changelog.txt) - [Commits](https://github.com/JeremySkinner/fluentvalidation/compare/8.1.3...8.2.0) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 7970bb5b4..d73405b0c 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -53,7 +53,7 @@ - + From fe719c3ca42ef7acbfa3b6be64a4565259716edf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 4 Apr 2019 13:13:35 +0200 Subject: [PATCH 110/178] Bump FluentValidation.ValidatorAttribute in /src/Miningcore (#589) Bumps [FluentValidation.ValidatorAttribute](https://github.com/JeremySkinner/fluentvalidation) from 8.1.3 to 8.2.0. - [Release notes](https://github.com/JeremySkinner/fluentvalidation/releases) - [Changelog](https://github.com/JeremySkinner/FluentValidation/blob/master/Changelog.txt) - [Commits](https://github.com/JeremySkinner/fluentvalidation/compare/8.1.3...8.2.0) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index d73405b0c..2e714a9b7 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -53,8 +53,8 @@ + - From 9b832e7219f40df8164189b00e330d24eb7e0bc6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 4 Apr 2019 13:16:06 +0200 Subject: [PATCH 111/178] Bump Autofac from 4.9.1 to 4.9.2 in /src/Miningcore (#583) Bumps [Autofac](https://github.com/autofac/Autofac) from 4.9.1 to 4.9.2. - [Release notes](https://github.com/autofac/Autofac/releases) - [Commits](https://github.com/autofac/Autofac/compare/v4.9.1...v4.9.2) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 2e714a9b7..651603730 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -50,7 +50,7 @@ - + From dd8474429e333cfd41f1d4cef3cdffefc7667191 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 4 Apr 2019 13:16:13 +0200 Subject: [PATCH 112/178] Bump McMaster.Extensions.CommandLineUtils in /src/Miningcore (#580) Bumps [McMaster.Extensions.CommandLineUtils](https://github.com/natemcmaster/CommandLineUtils) from 2.3.2 to 2.3.3. - [Release notes](https://github.com/natemcmaster/CommandLineUtils/releases) - [Changelog](https://github.com/natemcmaster/CommandLineUtils/blob/master/CHANGELOG.md) - [Commits](https://github.com/natemcmaster/CommandLineUtils/compare/v2.3.2...v2.3.3) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 651603730..b02fd48ea 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -57,7 +57,7 @@ - + From cea10d17bb9017a57a53c51ea12fad1762e5ba6d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 4 Apr 2019 13:17:21 +0200 Subject: [PATCH 113/178] Bump AspNetCoreRateLimit from 3.0.2 to 3.0.3 in /src/Miningcore (#579) Bumps [AspNetCoreRateLimit](https://github.com/stefanprodan/AspNetCoreRateLimit) from 3.0.2 to 3.0.3. - [Release notes](https://github.com/stefanprodan/AspNetCoreRateLimit/releases) - [Commits](https://github.com/stefanprodan/AspNetCoreRateLimit/commits/3.0.3) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index b02fd48ea..64b89d179 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -49,7 +49,7 @@ - + From 46361d30af47a2d0de221c9a93dfb5a4d557496f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 4 Apr 2019 13:18:02 +0200 Subject: [PATCH 114/178] Bump Polly from 7.0.3 to 7.1.0 in /src/Miningcore (#578) Bumps [Polly](https://github.com/App-vNext/Polly) from 7.0.3 to 7.1.0. - [Release notes](https://github.com/App-vNext/Polly/releases) - [Changelog](https://github.com/App-vNext/Polly/blob/master/CHANGELOG.md) - [Commits](https://github.com/App-vNext/Polly/commits) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 64b89d179..7846bf12e 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -69,9 +69,9 @@ - + - + From 727fa6bda24c3cd3466c2fb5f74451527f3c93e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 4 Apr 2019 13:19:02 +0200 Subject: [PATCH 115/178] Bump prometheus-net.AspNetCore from 3.0.3 to 3.1.0 in /src/Miningcore (#588) Bumps [prometheus-net.AspNetCore](https://github.com/prometheus-net/prometheus-net) from 3.0.3 to 3.1.0. - [Release notes](https://github.com/prometheus-net/prometheus-net/releases) - [Changelog](https://github.com/prometheus-net/prometheus-net/blob/master/History) - [Commits](https://github.com/prometheus-net/prometheus-net/compare/v3.0.3...v3.1.0) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 7846bf12e..2f2fa34fe 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -70,8 +70,8 @@ - + From 34795877504c4f133bb05f4018029b776849376a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 4 Apr 2019 13:19:22 +0200 Subject: [PATCH 116/178] Bump JetBrains.Annotations from 2018.3.0 to 2019.1.1 in /src/Miningcore (#587) Bumps JetBrains.Annotations from 2018.3.0 to 2019.1.1. Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 2f2fa34fe..d66acb936 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -55,7 +55,7 @@ - + From 82d8dbdc2a1fc496c8d219819a2e7fcc27304b69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 4 Apr 2019 13:19:32 +0200 Subject: [PATCH 117/178] Bump Dapper from 1.50.7 to 1.60.6 in /src/Miningcore (#586) Bumps [Dapper](https://github.com/StackExchange/Dapper) from 1.50.7 to 1.60.6. - [Release notes](https://github.com/StackExchange/Dapper/releases) - [Commits](https://github.com/StackExchange/Dapper/commits) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index d66acb936..f9068489a 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -52,7 +52,7 @@ - + From 31a583b61cfd02ec228003e2b064c3a90504a586 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Thu, 4 Apr 2019 13:26:02 +0200 Subject: [PATCH 118/178] .editorconfig --- .editorconfig | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..a8178cd58 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.cs] + +# Tab indentation (no size specified) +[Makefile] +indent_style = tab + +# Matches the exact files either package.json or .travis.yml +[{package.json,.travis.yml}] +indent_style = space +indent_size = 2 From 82d57285b743be736f4632537e3ea830d126de2b Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Thu, 4 Apr 2019 13:28:24 +0200 Subject: [PATCH 119/178] Move editorconfig --- .editorconfig => src/Miningcore/.editorconfig | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .editorconfig => src/Miningcore/.editorconfig (100%) diff --git a/.editorconfig b/src/Miningcore/.editorconfig similarity index 100% rename from .editorconfig rename to src/Miningcore/.editorconfig From 7f2e7ba60e923fd2ad68ef45caf51ad3eab55ae8 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Thu, 4 Apr 2019 13:42:12 +0200 Subject: [PATCH 120/178] Formatting pass --- src/Miningcore/.editorconfig | 5 + .../Api/Controllers/AdminApiController.cs | 2 +- .../Api/Controllers/ClusterApiController.cs | 20 ++-- .../Api/Controllers/PoolApiController.cs | 48 ++++---- .../Api/Extensions/MiningPoolExtensions.cs | 4 +- .../ApiExceptionHandlingMiddleware.cs | 4 +- .../IPAccessWhitelistMiddleware.cs | 6 +- .../WebSocketNotificationsRelay.cs | 4 +- src/Miningcore/AutofacMetadata.cs | 4 +- src/Miningcore/AutofacModule.cs | 4 +- .../Banning/IntegratedBanManager.cs | 2 +- .../Blockchain/Bitcoin/BitcoinJob.cs | 54 ++++----- .../Blockchain/Bitcoin/BitcoinJobManager.cs | 28 ++--- .../Bitcoin/BitcoinJobManagerBase.cs | 80 ++++++------- .../Bitcoin/BitcoinPayoutHandler.cs | 28 ++--- .../Blockchain/Bitcoin/BitcoinPool.cs | 44 ++++---- .../Blockchain/Cryptonote/CryptonoteJob.cs | 26 ++--- .../Cryptonote/CryptonoteJobManager.cs | 96 ++++++++-------- .../Cryptonote/CryptonotePayoutHandler.cs | 62 +++++----- .../Blockchain/Cryptonote/CryptonotePool.cs | 44 ++++---- .../DaemonResponses/TransferResponse.cs | 2 +- .../Custom/BitcoinGold/BitcoinGoldJob.cs | 24 ++-- .../Equihash/Custom/Minexcoin/MinexcoinJob.cs | 2 +- .../Blockchain/Equihash/EquihashJob.cs | 60 +++++----- .../Blockchain/Equihash/EquihashJobManager.cs | 36 +++--- .../Equihash/EquihashPayoutHandler.cs | 42 +++---- .../Blockchain/Equihash/EquihashPool.cs | 46 ++++---- .../Blockchain/Equihash/EquihashUtils.cs | 4 +- .../Blockchain/Ethereum/EthereumJob.cs | 18 +-- .../Blockchain/Ethereum/EthereumJobManager.cs | 104 ++++++++--------- .../Ethereum/EthereumPayoutHandler.cs | 48 ++++---- .../Blockchain/Ethereum/EthereumPool.cs | 42 +++---- .../Blockchain/Ethereum/EthereumUtils.cs | 10 +- .../Blockchain/ExtraNonceProviderBase.cs | 2 +- src/Miningcore/Blockchain/JobManagerBase.cs | 2 +- .../Configuration/ClusterConfigExtensions.cs | 16 +-- .../Configuration/ClusterConfigValidation.cs | 8 +- .../Configuration/CoinTemplateLoader.cs | 18 +-- src/Miningcore/Contracts/Contract.cs | 6 +- src/Miningcore/Crypto/HashAlgorithmFactory.cs | 8 +- .../Crypto/Hashing/Algorithms/Kezzak.cs | 4 +- .../Crypto/Hashing/Algorithms/ScryptN.cs | 4 +- .../Crypto/Hashing/Algorithms/Sha256D.cs | 2 +- .../Crypto/Hashing/Algorithms/Sha256S.cs | 2 +- .../Crypto/Hashing/Equihash/EquihashSolver.cs | 2 +- .../Hashing/Equihash/EquihashSolverFactory.cs | 4 +- src/Miningcore/Crypto/Hashing/Ethash/Cache.cs | 8 +- src/Miningcore/Crypto/Hashing/Ethash/Dag.cs | 20 ++-- .../Crypto/Hashing/Ethash/EthashFull.cs | 8 +- src/Miningcore/Crypto/MerkleTree.cs | 6 +- .../DaemonInterface/DaemonClient.cs | 42 +++---- src/Miningcore/Extensions/ArrayExtensions.cs | 6 +- .../Extensions/ConnectionFactoryExtensions.cs | 6 +- .../Extensions/DictionaryExtensions.cs | 2 +- .../Extensions/HttpContextExtensions.cs | 2 +- .../Extensions/LoggingExtensions.cs | 4 +- .../Extensions/MessageBusExtensions.cs | 12 +- src/Miningcore/Extensions/NumberExtensions.cs | 4 +- .../Extensions/PipelineExtensions.cs | 2 +- .../Extensions/SerializationExtensions.cs | 2 +- src/Miningcore/Extensions/StringExtensions.cs | 28 ++--- src/Miningcore/Extensions/ZmqExtensions.cs | 20 ++-- src/Miningcore/JsonRpc/JsonRpcRequest.cs | 2 +- src/Miningcore/JsonRpc/JsonRpcResponse.cs | 4 +- src/Miningcore/Messaging/MessageBus.cs | 4 +- src/Miningcore/Mining/BtStreamReceiver.cs | 40 +++---- src/Miningcore/Mining/PoolBase.cs | 40 +++---- src/Miningcore/Mining/ShareReceiver.cs | 62 +++++----- src/Miningcore/Mining/ShareRecorder.cs | 32 +++--- src/Miningcore/Mining/ShareRelay.cs | 10 +- src/Miningcore/Mining/StatsRecorder.cs | 10 +- src/Miningcore/Mining/WorkerContextBase.cs | 4 +- src/Miningcore/Native/LibCryptonight.cs | 12 +- src/Miningcore/Native/LibCryptonote.cs | 18 +-- .../Notifications/NotificationService.cs | 12 +- .../PaymentSchemes/PPLNSPaymentScheme.cs | 26 ++--- .../PaymentSchemes/SoloPaymentScheme.cs | 8 +- src/Miningcore/Payments/PayoutHandlerBase.cs | 6 +- src/Miningcore/Payments/PayoutManager.cs | 26 ++--- .../Repositories/BalanceRepository.cs | 2 +- .../Postgres/Repositories/BlockRepository.cs | 22 ++-- .../Repositories/PaymentRepository.cs | 2 +- .../Postgres/Repositories/ShareRepository.cs | 10 +- .../Postgres/Repositories/StatsRepository.cs | 38 +++---- src/Miningcore/Program.cs | 96 ++++++++-------- .../HexToByteArrayJsonConverter.cs | 4 +- .../HexToIntegralTypeJsonConverter.cs | 10 +- src/Miningcore/Stratum/StratumClient.cs | 64 +++++------ src/Miningcore/Stratum/StratumServer.cs | 50 ++++----- src/Miningcore/Util/BigRational.cs | 106 +++++++++--------- src/Miningcore/Util/CircularBuffer.cs | 28 ++--- src/Miningcore/Util/ScheduledSubject.cs | 6 +- src/Miningcore/VarDiff/VarDiffManager.cs | 20 ++-- 93 files changed, 1016 insertions(+), 1011 deletions(-) diff --git a/src/Miningcore/.editorconfig b/src/Miningcore/.editorconfig index a8178cd58..f26c4c150 100644 --- a/src/Miningcore/.editorconfig +++ b/src/Miningcore/.editorconfig @@ -10,6 +10,11 @@ indent_size = 4 trim_trailing_whitespace = true [*.cs] +csharp_space_after_cast = true +csharp_space_after_keywords_in_control_flow_statements = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_around_binary_operators = true # Tab indentation (no size specified) [Makefile] diff --git a/src/Miningcore/Api/Controllers/AdminApiController.cs b/src/Miningcore/Api/Controllers/AdminApiController.cs index 942dc4409..46c89128d 100644 --- a/src/Miningcore/Api/Controllers/AdminApiController.cs +++ b/src/Miningcore/Api/Controllers/AdminApiController.cs @@ -70,7 +70,7 @@ public async Task AddMinerBalanceAsync(AddBalanceRequest request) { request.Usage = request.Usage?.Trim(); - if (string.IsNullOrEmpty(request.Usage)) + if(string.IsNullOrEmpty(request.Usage)) request.Usage = $"Admin balance change from {Request.HttpContext.Connection.RemoteIpAddress}"; var oldBalance = await cf.Run(con => balanceRepo.GetBalanceAsync(con, request.PoolId, request.Address)); diff --git a/src/Miningcore/Api/Controllers/ClusterApiController.cs b/src/Miningcore/Api/Controllers/ClusterApiController.cs index a8a8ccd83..6ea1bff9e 100644 --- a/src/Miningcore/Api/Controllers/ClusterApiController.cs +++ b/src/Miningcore/Api/Controllers/ClusterApiController.cs @@ -62,33 +62,33 @@ public ClusterApiController(IComponentContext ctx) var blocks = (await cf.Run(con => blocksRepo.PageBlocksAsync(con, blockStates, page, pageSize))) .Select(mapper.Map) - .Where(x=> enabledPools.Contains(x.PoolId)) + .Where(x => enabledPools.Contains(x.PoolId)) .ToArray(); // enrich blocks var blocksByPool = blocks.GroupBy(x => x.PoolId); - foreach (var poolBlocks in blocksByPool) + foreach(var poolBlocks in blocksByPool) { var pool = GetPoolNoThrow(poolBlocks.Key); - if (pool == null) + if(pool == null) continue; var blockInfobaseDict = pool.Template.ExplorerBlockLinks; - + // compute infoLink - if (blockInfobaseDict != null) + if(blockInfobaseDict != null) { - foreach (var block in poolBlocks) + foreach(var block in poolBlocks) { blockInfobaseDict.TryGetValue(!string.IsNullOrEmpty(block.Type) ? block.Type : "block", out var blockInfobaseUrl); - if (!string.IsNullOrEmpty(blockInfobaseUrl)) + if(!string.IsNullOrEmpty(blockInfobaseUrl)) { - if (blockInfobaseUrl.Contains(CoinMetaData.BlockHeightPH)) + if(blockInfobaseUrl.Contains(CoinMetaData.BlockHeightPH)) block.InfoLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHeightPH, block.BlockHeight.ToString(CultureInfo.InvariantCulture)); - else if (blockInfobaseUrl.Contains(CoinMetaData.BlockHashPH) && !string.IsNullOrEmpty(block.Hash)) + else if(blockInfobaseUrl.Contains(CoinMetaData.BlockHashPH) && !string.IsNullOrEmpty(block.Hash)) block.InfoLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHashPH, block.Hash); } } @@ -102,7 +102,7 @@ public ClusterApiController(IComponentContext ctx) private PoolConfig GetPoolNoThrow(string poolId) { - if (string.IsNullOrEmpty(poolId)) + if(string.IsNullOrEmpty(poolId)) return null; var pool = clusterConfig.Pools.FirstOrDefault(x => x.Id == poolId && x.Enabled); diff --git a/src/Miningcore/Api/Controllers/PoolApiController.cs b/src/Miningcore/Api/Controllers/PoolApiController.cs index 78cf75dc6..f079ce169 100644 --- a/src/Miningcore/Api/Controllers/PoolApiController.cs +++ b/src/Miningcore/Api/Controllers/PoolApiController.cs @@ -121,7 +121,7 @@ public async Task GetPoolPerformanceAsync(string poolId, var end = clock.Now; DateTime start; - switch (range) + switch(range) { case SampleRange.Day: start = end.AddDays(-1); @@ -181,18 +181,18 @@ public async Task PagePoolMinersAsync( // enrich blocks var blockInfobaseDict = pool.Template.ExplorerBlockLinks; - foreach (var block in blocks) + foreach(var block in blocks) { // compute infoLink - if (blockInfobaseDict != null) + if(blockInfobaseDict != null) { blockInfobaseDict.TryGetValue(!string.IsNullOrEmpty(block.Type) ? block.Type : "block", out var blockInfobaseUrl); - if (!string.IsNullOrEmpty(blockInfobaseUrl)) + if(!string.IsNullOrEmpty(blockInfobaseUrl)) { - if (blockInfobaseUrl.Contains(CoinMetaData.BlockHeightPH)) + if(blockInfobaseUrl.Contains(CoinMetaData.BlockHeightPH)) block.InfoLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHeightPH, block.BlockHeight.ToString(CultureInfo.InvariantCulture)); - else if (blockInfobaseUrl.Contains(CoinMetaData.BlockHashPH) && !string.IsNullOrEmpty(block.Hash)) + else if(blockInfobaseUrl.Contains(CoinMetaData.BlockHashPH) && !string.IsNullOrEmpty(block.Hash)) block.InfoLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHashPH, block.Hash); } } @@ -216,14 +216,14 @@ public async Task PagePoolMinersAsync( var txInfobaseUrl = pool.Template.ExplorerTxLink; var addressInfobaseUrl = pool.Template.ExplorerTxLink; - foreach (var payment in payments) + foreach(var payment in payments) { // compute transaction infoLink - if (!string.IsNullOrEmpty(txInfobaseUrl)) + if(!string.IsNullOrEmpty(txInfobaseUrl)) payment.TransactionInfoLink = string.Format(txInfobaseUrl, payment.TransactionConfirmationData); // pool wallet link - if (!string.IsNullOrEmpty(addressInfobaseUrl)) + if(!string.IsNullOrEmpty(addressInfobaseUrl)) payment.AddressInfoLink = string.Format(addressInfobaseUrl, payment.Address); } @@ -236,7 +236,7 @@ public async Task PagePoolMinersAsync( { var pool = GetPool(poolId); - if (string.IsNullOrEmpty(address)) + if(string.IsNullOrEmpty(address)) throw new ApiException($"Invalid or missing miner address", HttpStatusCode.NotFound); var statsResult = await cf.RunTx((con, tx) => @@ -244,19 +244,19 @@ public async Task PagePoolMinersAsync( Responses.MinerStats stats = null; - if (statsResult != null) + if(statsResult != null) { stats = mapper.Map(statsResult); // optional fields - if (statsResult.LastPayment != null) + if(statsResult.LastPayment != null) { // Set timestamp of last payment stats.LastPayment = statsResult.LastPayment.Created; // Compute info link var baseUrl = pool.Template.ExplorerTxLink; - if (!string.IsNullOrEmpty(baseUrl)) + if(!string.IsNullOrEmpty(baseUrl)) stats.LastPaymentLink = string.Format(baseUrl, statsResult.LastPayment.TransactionConfirmationData); } @@ -272,7 +272,7 @@ public async Task PagePoolMinersAsync( { var pool = GetPool(poolId); - if (string.IsNullOrEmpty(address)) + if(string.IsNullOrEmpty(address)) throw new ApiException($"Invalid or missing miner address", HttpStatusCode.NotFound); var payments = (await cf.Run(con => paymentsRepo.PagePaymentsAsync( @@ -284,14 +284,14 @@ public async Task PagePoolMinersAsync( var txInfobaseUrl = pool.Template.ExplorerTxLink; var addressInfobaseUrl = pool.Template.ExplorerTxLink; - foreach (var payment in payments) + foreach(var payment in payments) { // compute transaction infoLink - if (!string.IsNullOrEmpty(txInfobaseUrl)) + if(!string.IsNullOrEmpty(txInfobaseUrl)) payment.TransactionInfoLink = string.Format(txInfobaseUrl, payment.TransactionConfirmationData); // pool wallet link - if (!string.IsNullOrEmpty(addressInfobaseUrl)) + if(!string.IsNullOrEmpty(addressInfobaseUrl)) payment.AddressInfoLink = string.Format(addressInfobaseUrl, payment.Address); } @@ -304,7 +304,7 @@ public async Task PagePoolMinersAsync( { var pool = GetPool(poolId); - if (string.IsNullOrEmpty(address)) + if(string.IsNullOrEmpty(address)) throw new ApiException($"Invalid or missing miner address", HttpStatusCode.NotFound); var balanceChanges = (await cf.Run(con => paymentsRepo.PageBalanceChangesAsync( @@ -321,7 +321,7 @@ public async Task PageMinerEarningsByDayAsync( { var pool = GetPool(poolId); - if (string.IsNullOrEmpty(address)) + if(string.IsNullOrEmpty(address)) throw new ApiException($"Invalid or missing miner address", HttpStatusCode.NotFound); var earnings = (await cf.Run(con => paymentsRepo.PageMinerPaymentsByDayAsync( @@ -337,7 +337,7 @@ public async Task PageMinerEarningsByDayAsync( { var pool = GetPool(poolId); - if (string.IsNullOrEmpty(address)) + if(string.IsNullOrEmpty(address)) throw new ApiException($"Invalid or missing miner address", HttpStatusCode.NotFound); var result = await GetMinerPerformanceInternal(mode, pool, address); @@ -349,12 +349,12 @@ public async Task PageMinerEarningsByDayAsync( private PoolConfig GetPool(string poolId) { - if (string.IsNullOrEmpty(poolId)) + if(string.IsNullOrEmpty(poolId)) throw new ApiException($"Invalid pool id", HttpStatusCode.NotFound); var pool = clusterConfig.Pools.FirstOrDefault(x => x.Id == poolId && x.Enabled); - if (pool == null) + if(pool == null) throw new ApiException($"Pool {poolId} is not known", HttpStatusCode.NotFound); return pool; @@ -371,7 +371,7 @@ private PoolConfig GetPool(string poolId) { case SampleRange.Day: // set range - if (end.Minute < 30) + if(end.Minute < 30) end = end.AddHours(-1); end = end.AddMinutes(-end.Minute); @@ -384,7 +384,7 @@ private PoolConfig GetPool(string poolId) break; case SampleRange.Month: - if (end.Hour < 12) + if(end.Hour < 12) end = end.AddDays(-1); end = end.Date; diff --git a/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs b/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs index b40f7f00e..6c5c3cc75 100644 --- a/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs +++ b/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs @@ -21,14 +21,14 @@ public static PoolInfo ToPoolInfo(this PoolConfig poolConfig, IMapper mapper, Pe // pool wallet link var addressInfobaseUrl = poolConfig.Template.ExplorerAccountLink; - if (!string.IsNullOrEmpty(addressInfobaseUrl)) + if(!string.IsNullOrEmpty(addressInfobaseUrl)) poolInfo.AddressInfoLink = string.Format(addressInfobaseUrl, poolInfo.Address); // pool fees poolInfo.PoolFeePercent = (float) poolConfig.RewardRecipients.Sum(x => x.Percentage); // strip security critical stuff - if (poolInfo.PaymentProcessing.Extra != null) + if(poolInfo.PaymentProcessing.Extra != null) { var extra = poolInfo.PaymentProcessing.Extra; diff --git a/src/Miningcore/Api/Middlewares/ApiExceptionHandlingMiddleware.cs b/src/Miningcore/Api/Middlewares/ApiExceptionHandlingMiddleware.cs index 125103fd5..1f7b1f767 100644 --- a/src/Miningcore/Api/Middlewares/ApiExceptionHandlingMiddleware.cs +++ b/src/Miningcore/Api/Middlewares/ApiExceptionHandlingMiddleware.cs @@ -20,7 +20,7 @@ public async Task InvokeAsync(HttpContext context) await next(context); } - catch (ApiException ex) + catch(ApiException ex) { await HandleResponseOverrideExceptionAsync(context, ex); } @@ -31,7 +31,7 @@ private static async Task HandleResponseOverrideExceptionAsync(HttpContext conte var response = context.Response; response.ContentType = "application/json"; - if (ex.ResponseStatusCode.HasValue) + if(ex.ResponseStatusCode.HasValue) response.StatusCode = ex.ResponseStatusCode.Value; await response.WriteAsync(ex.Message).ConfigureAwait(false); diff --git a/src/Miningcore/Api/Middlewares/IPAccessWhitelistMiddleware.cs b/src/Miningcore/Api/Middlewares/IPAccessWhitelistMiddleware.cs index 22c7d609b..c309ee12a 100644 --- a/src/Miningcore/Api/Middlewares/IPAccessWhitelistMiddleware.cs +++ b/src/Miningcore/Api/Middlewares/IPAccessWhitelistMiddleware.cs @@ -24,15 +24,15 @@ public IPAccessWhitelistMiddleware(RequestDelegate next, string[] locations, IPA public async Task Invoke(HttpContext context) { - if (locations.Any(x=> context.Request.Path.Value.StartsWith(x))) + if(locations.Any(x => context.Request.Path.Value.StartsWith(x))) { var remoteAddress = context.Connection.RemoteIpAddress; - if (!whitelist.Any(x => x.Equals(remoteAddress))) + if(!whitelist.Any(x => x.Equals(remoteAddress))) { logger.Info(() => $"Unauthorized request attempt to {context.Request.Path.Value} from {remoteAddress}"); - context.Response.StatusCode = (int)HttpStatusCode.Forbidden; + context.Response.StatusCode = (int) HttpStatusCode.Forbidden; await context.Response.WriteAsync("You are not in my access list. Good Bye.\n"); return; } diff --git a/src/Miningcore/Api/WebSocketNotifications/WebSocketNotificationsRelay.cs b/src/Miningcore/Api/WebSocketNotifications/WebSocketNotificationsRelay.cs index b6d2266ba..ffb4f7a0a 100644 --- a/src/Miningcore/Api/WebSocketNotifications/WebSocketNotificationsRelay.cs +++ b/src/Miningcore/Api/WebSocketNotifications/WebSocketNotificationsRelay.cs @@ -21,7 +21,7 @@ namespace Miningcore.Api { public class WebSocketNotificationsRelay : WebSocketHandler { - public WebSocketNotificationsRelay(WebSocketConnectionManager webSocketConnectionManager, IComponentContext ctx) : + public WebSocketNotificationsRelay(WebSocketConnectionManager webSocketConnectionManager, IComponentContext ctx) : base(webSocketConnectionManager, new StringMethodInvocationStrategy()) { messageBus = ctx.Resolve(); @@ -78,7 +78,7 @@ private async Task BroadcastNotification(WsNotificationType type, T notificat await SendMessageToAllAsync(msg); } - catch (Exception ex) + catch(Exception ex) { logger.Error(ex); } diff --git a/src/Miningcore/AutofacMetadata.cs b/src/Miningcore/AutofacMetadata.cs index c591c2186..c1d08aef9 100644 --- a/src/Miningcore/AutofacMetadata.cs +++ b/src/Miningcore/AutofacMetadata.cs @@ -28,8 +28,8 @@ public class CoinFamilyAttribute : Attribute { public CoinFamilyAttribute(IDictionary values) { - if (values.ContainsKey(nameof(SupportedFamilies))) - SupportedFamilies = (CoinFamily[])values[nameof(SupportedFamilies)]; + if(values.ContainsKey(nameof(SupportedFamilies))) + SupportedFamilies = (CoinFamily[]) values[nameof(SupportedFamilies)]; } public CoinFamilyAttribute(params CoinFamily[] supportedFamilies) diff --git a/src/Miningcore/AutofacModule.cs b/src/Miningcore/AutofacModule.cs index cc165b755..ad0dfb520 100644 --- a/src/Miningcore/AutofacModule.cs +++ b/src/Miningcore/AutofacModule.cs @@ -94,7 +94,7 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType() .SingleInstance(); - + builder.RegisterType() .SingleInstance(); @@ -129,7 +129,7 @@ protected override void Load(ContainerBuilder builder) .PropertiesAutowired() .AsSelf() .SingleInstance(); - + ////////////////////// // Payment Schemes diff --git a/src/Miningcore/Banning/IntegratedBanManager.cs b/src/Miningcore/Banning/IntegratedBanManager.cs index bb5f07a47..01ea1b57d 100644 --- a/src/Miningcore/Banning/IntegratedBanManager.cs +++ b/src/Miningcore/Banning/IntegratedBanManager.cs @@ -47,7 +47,7 @@ public void Ban(IPAddress address, TimeSpan duration) Contract.Requires(duration.TotalMilliseconds > 0, $"{nameof(duration)} must not be empty"); // don't ban 127.0.0.1 - if (address.Equals(IPAddress.Loopback) || address.Equals(IPAddress.IPv6Loopback)) + if(address.Equals(IPAddress.Loopback) || address.Equals(IPAddress.IPv6Loopback)) return; cache.Set(address.ToString(), string.Empty, duration); diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs index a67d1ea1c..ae298b3ca 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs @@ -124,7 +124,7 @@ protected virtual void BuildCoinbase() bs.ReadWrite(ref txVersion); // timestamp for POS coins - if (isPoS) + if(isPoS) { var timestamp = BlockTemplate.CurTime; bs.ReadWrite(ref timestamp); @@ -173,13 +173,13 @@ protected virtual void BuildCoinbase() protected virtual void AppendCoinbaseFinal(BitcoinStream bs) { - if (!string.IsNullOrEmpty(txComment)) + if(!string.IsNullOrEmpty(txComment)) { var data = Encoding.ASCII.GetBytes(txComment); bs.ReadWriteAsVarString(ref data); } - if (coin.HasMasterNodes && !string.IsNullOrEmpty(masterNodeParameters.CoinbasePayload)) + if(coin.HasMasterNodes && !string.IsNullOrEmpty(masterNodeParameters.CoinbasePayload)) { var data = masterNodeParameters.CoinbasePayload.HexToByteArray(); bs.ReadWriteAsVarString(ref data); @@ -191,7 +191,7 @@ protected virtual byte[] SerializeOutputTransaction(Transaction tx) var withDefaultWitnessCommitment = !string.IsNullOrEmpty(BlockTemplate.DefaultWitnessCommitment); var outputCount = (uint) tx.Outputs.Count; - if (withDefaultWitnessCommitment) + if(withDefaultWitnessCommitment) outputCount++; using(var stream = new MemoryStream()) @@ -206,7 +206,7 @@ protected virtual byte[] SerializeOutputTransaction(Transaction tx) uint rawLength; // serialize witness (segwit) - if (withDefaultWitnessCommitment) + if(withDefaultWitnessCommitment) { amount = 0; raw = BlockTemplate.DefaultWitnessCommitment.HexToByteArray(); @@ -245,7 +245,7 @@ protected virtual Script GenerateScriptSigInitial() ops.Add(Op.GetPushOp(BlockTemplate.Height)); // optionally push aux-flags - if (!string.IsNullOrEmpty(BlockTemplate.CoinbaseAux?.Flags)) + if(!string.IsNullOrEmpty(BlockTemplate.CoinbaseAux?.Flags)) ops.Add(Op.GetPushOp(BlockTemplate.CoinbaseAux.Flags.HexToByteArray())); // push timestamp @@ -274,7 +274,7 @@ protected virtual Transaction CreatePayeeOutputTransaction() var tx = Transaction.Create(network); - if (payeeParameters?.PayeeAmount > 0) + if(payeeParameters?.PayeeAmount > 0) { var payeeReward = new Money(payeeParameters.PayeeAmount.Value, MoneyUnit.Satoshi); rewardToPool -= payeeReward; @@ -298,7 +298,7 @@ protected bool RegisterSubmit(string extraNonce1, string extraNonce2, string nTi lock(submissions) { - if (submissions.Contains(key)) + if(submissions.Contains(key)) return false; submissions.Add(key); @@ -315,7 +315,7 @@ protected byte[] SerializeHeader(Span coinbaseHash, uint nTime, uint nonce var version = BlockTemplate.Version; // Overt-ASIC boost - if (versionMask.HasValue && versionBits.HasValue) + if(versionMask.HasValue && versionBits.HasValue) version = (version & ~versionMask.Value) | (versionBits.Value & versionMask.Value); #pragma warning disable 618 @@ -359,14 +359,14 @@ protected virtual (Share Share, string BlockHex) ProcessShareInternal( var isBlockCandidate = headerValue <= blockTargetValue; // test if share meets at least workers current difficulty - if (!isBlockCandidate && ratio < 0.99) + if(!isBlockCandidate && ratio < 0.99) { // check if share matched the previous difficulty from before a vardiff retarget - if (context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue) + if(context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue) { ratio = shareDiff / context.PreviousDifficulty.Value; - if (ratio < 0.99) + if(ratio < 0.99) throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); // use previous difficulty @@ -384,7 +384,7 @@ protected virtual (Share Share, string BlockHex) ProcessShareInternal( Difficulty = stratumDifficulty / shareMultiplier, }; - if (isBlockCandidate) + if(isBlockCandidate) { result.IsBlockCandidate = true; @@ -432,7 +432,7 @@ protected virtual byte[] SerializeBlock(byte[] header, byte[] coinbase) bs.ReadWrite(ref rawTransactionBuffer); // POS coins require a zero byte appended to block which the daemon replaces with the signature - if (isPoS) + if(isPoS) bs.ReadWrite((byte) 0); return stream.ToArray(); @@ -475,19 +475,19 @@ protected virtual Transaction CreateMasternodeOutputTransaction() protected virtual Money CreateMasternodeOutputs(Transaction tx, Money reward) { - if (masterNodeParameters.Masternode != null) + if(masterNodeParameters.Masternode != null) { Masternode[] masternodes; // Dash v13 Multi-Master-Nodes - if (masterNodeParameters.Masternode.Type == JTokenType.Array) + if(masterNodeParameters.Masternode.Type == JTokenType.Array) masternodes = masterNodeParameters.Masternode.ToObject(); else masternodes = new[] { masterNodeParameters.Masternode.ToObject() }; foreach(var masterNode in masternodes) { - if (!string.IsNullOrEmpty(masterNode.Payee)) + if(!string.IsNullOrEmpty(masterNode.Payee)) { var payeeAddress = BitcoinUtils.AddressToDestination(masterNode.Payee, network); var payeeReward = masterNode.Amount; @@ -500,9 +500,9 @@ protected virtual Money CreateMasternodeOutputs(Transaction tx, Money reward) } } - if (masterNodeParameters.SuperBlocks != null && masterNodeParameters.SuperBlocks.Length > 0) + if(masterNodeParameters.SuperBlocks != null && masterNodeParameters.SuperBlocks.Length > 0) { - foreach (var superBlock in masterNodeParameters.SuperBlocks) + foreach(var superBlock in masterNodeParameters.SuperBlocks) { var payeeAddress = BitcoinUtils.AddressToDestination(superBlock.Payee, network); var payeeReward = superBlock.Amount; @@ -514,7 +514,7 @@ protected virtual Money CreateMasternodeOutputs(Transaction tx, Money reward) } } - if (!string.IsNullOrEmpty(masterNodeParameters.Payee)) + if(!string.IsNullOrEmpty(masterNodeParameters.Payee)) { var payeeAddress = BitcoinUtils.AddressToDestination(masterNodeParameters.Payee, network); var payeeReward = masterNodeParameters.PayeeAmount ?? (reward / 5); @@ -570,7 +570,7 @@ public void Init(BlockTemplate blockTemplate, string jobId, txComment = !string.IsNullOrEmpty(extraPoolConfig?.CoinbaseTxComment) ? extraPoolConfig.CoinbaseTxComment : coin.CoinbaseTxComment; - if (coin.HasMasterNodes) + if(coin.HasMasterNodes) { masterNodeParameters = BlockTemplate.Extra.SafeExtensionDataAs(); @@ -589,7 +589,7 @@ public void Init(BlockTemplate blockTemplate, string jobId, this.headerHasher = headerHasher; this.blockHasher = blockHasher; - if (!string.IsNullOrEmpty(BlockTemplate.Target)) + if(!string.IsNullOrEmpty(BlockTemplate.Target)) blockTargetValue = new uint256(BlockTemplate.Target); else { @@ -636,15 +636,15 @@ public virtual (Share Share, string BlockHex) ProcessShare(StratumClient worker, var context = worker.ContextAs(); // validate nTime - if (nTime.Length != 8) + if(nTime.Length != 8) throw new StratumException(StratumError.Other, "incorrect size of ntime"); var nTimeInt = uint.Parse(nTime, NumberStyles.HexNumber); - if (nTimeInt < BlockTemplate.CurTime || nTimeInt > ((DateTimeOffset) clock.Now).ToUnixTimeSeconds() + 7200) + if(nTimeInt < BlockTemplate.CurTime || nTimeInt > ((DateTimeOffset) clock.Now).ToUnixTimeSeconds() + 7200) throw new StratumException(StratumError.Other, "ntime out of range"); // validate nonce - if (nonce.Length != 8) + if(nonce.Length != 8) throw new StratumException(StratumError.Other, "incorrect size of nonce"); var nonceInt = uint.Parse(nonce, NumberStyles.HexNumber); @@ -657,12 +657,12 @@ public virtual (Share Share, string BlockHex) ProcessShare(StratumClient worker, versionBitsInt = uint.Parse(versionBits, NumberStyles.HexNumber); // enforce that only bits covered by current mask are changed by miner - if ((versionBitsInt & ~context.VersionRollingMask.Value) != 0) + if((versionBitsInt & ~context.VersionRollingMask.Value) != 0) throw new StratumException(StratumError.Other, "rolling-version mask violation"); } // dupe check - if (!RegisterSubmit(context.ExtraNonce1, extraNonce2, nTime, nonce)) + if(!RegisterSubmit(context.ExtraNonce1, extraNonce2, nTime, nonce)) throw new StratumException(StratumError.DuplicateShare, "duplicate share"); return ProcessShareInternal(worker, extraNonce2, nTimeInt, nonceInt, versionBitsInt); diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index 37ba72ee5..f87122b83 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -90,13 +90,13 @@ private BitcoinJob CreateJob() try { - if (forceUpdate) + if(forceUpdate) lastJobRebroadcast = clock.Now; var response = string.IsNullOrEmpty(json) ? await GetBlockTemplateAsync() : GetBlockTemplateFromJson(json); // may happen if daemon is currently not connected to peers - if (response.Error != null) + if(response.Error != null) { logger.Warn(() => $"Unable to update job. Daemon responded with: {response.Error.Message} Code {response.Error.Code}"); return (false, forceUpdate); @@ -113,7 +113,7 @@ private BitcoinJob CreateJob() if(isNew) messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); - if (isNew || forceUpdate) + if(isNew || forceUpdate) { job = CreateJob(); @@ -122,11 +122,11 @@ private BitcoinJob CreateJob() ShareMultiplier, coin.CoinbaseHasherValue, coin.HeaderHasherValue, !isPoS ? coin.BlockHasherValue : coin.PoSBlockHasherValue ?? coin.BlockHasherValue); - lock (jobLock) + lock(jobLock) { - if (isNew) + if(isNew) { - if (via != null) + if(via != null) logger.Info(() => $"Detected new block {blockTemplate.Height} via {via}"); else logger.Info(() => $"Detected new block {blockTemplate.Height}"); @@ -142,7 +142,7 @@ private BitcoinJob CreateJob() validJobs.Insert(0, job); // trim active jobs - while (validJobs.Count > maxActiveJobs) + while(validJobs.Count > maxActiveJobs) validJobs.RemoveAt(validJobs.Count - 1); } @@ -152,7 +152,7 @@ private BitcoinJob CreateJob() return (isNew, forceUpdate); } - catch (Exception ex) + catch(Exception ex) { logger.Error(ex, () => $"Error during {nameof(UpdateJob)}"); } @@ -174,7 +174,7 @@ public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfi extraPoolConfig = poolConfig.Extra.SafeExtensionDataAs(); extraPoolPaymentProcessingConfig = poolConfig.PaymentProcessing?.Extra?.SafeExtensionDataAs(); - if (extraPoolConfig?.MaxActiveJobs.HasValue == true) + if(extraPoolConfig?.MaxActiveJobs.HasValue == true) maxActiveJobs = extraPoolConfig.MaxActiveJobs.Value; hasLegacyDaemon = extraPoolConfig?.HasLegacyDaemon == true; @@ -209,7 +209,7 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob logger.LogInvoke(new[] { worker.ConnectionId }); - if (!(submission is object[] submitParams)) + if(!(submission is object[] submitParams)) throw new StratumException(StratumError.Other, "invalid params"); var context = worker.ContextAs(); @@ -222,7 +222,7 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob var nonce = submitParams[4] as string; var versionBits = context.VersionRollingMask.HasValue ? submitParams[5] as string : null; - if (string.IsNullOrEmpty(workerValue)) + if(string.IsNullOrEmpty(workerValue)) throw new StratumException(StratumError.Other, "missing or invalid workername"); BitcoinJob job; @@ -232,7 +232,7 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob job = validJobs.FirstOrDefault(x => x.JobId == jobId); } - if (job == null) + if(job == null) throw new StratumException(StratumError.JobNotFound, "job not found"); // extract worker/miner/payoutid @@ -253,7 +253,7 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob share.Created = clock.Now; // if block candidate, submit & check if accepted by network - if (share.IsBlockCandidate) + if(share.IsBlockCandidate) { logger.Info(() => $"Submitting block {share.BlockHeight} [{share.BlockHash}]"); @@ -262,7 +262,7 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob // is it still a block candidate? share.IsBlockCandidate = acceptResponse.Accepted; - if (share.IsBlockCandidate) + if(share.IsBlockCandidate) { logger.Info(() => $"Daemon accepted block {share.BlockHeight} [{share.BlockHash}] submitted by {minerName}"); diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index bdb6997db..204a47e9b 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -105,7 +105,7 @@ protected virtual void SetupJobUpdates() blockSubmission.Select(x => (false, "Block-submission", (string) null)) }; - if (extraPoolConfig?.BtStream == null) + if(extraPoolConfig?.BtStream == null) { // collect ports var zmq = poolConfig.Daemons @@ -118,14 +118,14 @@ protected virtual void SetupJobUpdates() return (Socket: extra.ZmqBlockNotifySocket, Topic: topic); }); - if (zmq.Count > 0) + if(zmq.Count > 0) { logger.Info(() => $"Subscribing to ZMQ push-updates from {string.Join(", ", zmq.Values)}"); var blockNotify = daemon.ZmqSubscribe(logger, zmq) .Select(msg => { - using (msg) + using(msg) { // We just take the second frame's raw data and turn it into a hex string. // If that string changes, we got an update (DistinctUntilChanged) @@ -147,7 +147,7 @@ protected virtual void SetupJobUpdates() triggers.Add(blockNotify); } - if (poolConfig.BlockRefreshInterval > 0) + if(poolConfig.BlockRefreshInterval > 0) { // periodically update block-template var pollingInterval = poolConfig.BlockRefreshInterval > 0 ? poolConfig.BlockRefreshInterval : 1000; @@ -177,7 +177,7 @@ protected virtual void SetupJobUpdates() { var btStream = BtStreamSubscribe(extraPoolConfig.BtStream); - if (poolConfig.JobRebroadcastTimeout > 0) + if(poolConfig.JobRebroadcastTimeout > 0) { var interval = TimeSpan.FromSeconds(Math.Max(1, poolConfig.JobRebroadcastTimeout - 0.1d)); @@ -207,7 +207,7 @@ protected virtual void SetupJobUpdates() .Where(x => x.IsNew || x.Force) .Do(x => { - if (x.IsNew) + if(x.IsNew) hasInitialBlockTemplate = true; }) .Select(x => GetJobParamsForStratum(x.IsNew)) @@ -217,7 +217,7 @@ protected virtual void SetupJobUpdates() protected virtual async Task ShowDaemonSyncProgressAsync() { - if (hasLegacyDaemon) + if(hasLegacyDaemon) { await ShowDaemonSyncProgressLegacyAsync(); return; @@ -225,18 +225,18 @@ protected virtual async Task ShowDaemonSyncProgressAsync() var infos = await daemon.ExecuteCmdAllAsync(logger, BitcoinCommands.GetBlockchainInfo); - if (infos.Length > 0) + if(infos.Length > 0) { var blockCount = infos .Max(x => x.Response?.Blocks); - if (blockCount.HasValue) + if(blockCount.HasValue) { // get list of peers and their highest block height to compare to ours var peerInfo = await daemon.ExecuteCmdAnyAsync(logger, BitcoinCommands.GetPeerInfo); var peers = peerInfo.Response; - if (peers != null && peers.Length > 0) + if(peers != null && peers.Length > 0) { var totalBlocks = peers.Max(x => x.StartingHeight); var percent = totalBlocks > 0 ? (double) blockCount / totalBlocks * 100 : 0; @@ -258,22 +258,22 @@ private async Task UpdateNetworkStatsAsync() new DaemonCmd(BitcoinCommands.GetNetworkHashPS) ); - if (results.Any(x => x.Error != null)) + if(results.Any(x => x.Error != null)) { var errors = results.Where(x => x.Error != null).ToArray(); - if (errors.Any()) + if(errors.Any()) logger.Warn(() => $"Error(s) refreshing network stats: {string.Join(", ", errors.Select(y => y.Error.Message))}"); } var miningInfoResponse = results[0].Response.ToObject(); var networkInfoResponse = results[1].Response.ToObject(); - BlockchainStats.NetworkHashrate = miningInfoResponse.NetworkHashps; + BlockchainStats.NetworkHashrate = miningInfoResponse.NetworkHashps; BlockchainStats.ConnectedPeers = networkInfoResponse.Connections; // Fall back to alternative RPC if coin does not report Network HPS (Digibyte) - if (BlockchainStats.NetworkHashrate == 0 && results[2].Error == null) + if(BlockchainStats.NetworkHashrate == 0 && results[2].Error == null) BlockchainStats.NetworkHashrate = results[2].Response.Value(); } @@ -298,7 +298,7 @@ private async Task UpdateNetworkStatsAsync() submitResult.Error?.Code.ToString(CultureInfo.InvariantCulture) ?? submitResult.Response?.ToString(); - if (!string.IsNullOrEmpty(submitError)) + if(!string.IsNullOrEmpty(submitError)) { logger.Warn(() => $"Block {share.BlockHeight} submission failed with: {submitError}"); messageBus.SendMessage(new AdminNotification("Block submission failed", $"Pool {poolConfig.Id} {(!string.IsNullOrEmpty(share.Source) ? $"[{share.Source.ToUpper()}] " : string.Empty)}failed to submit block {share.BlockHeight}: {submitError}")); @@ -310,7 +310,7 @@ private async Task UpdateNetworkStatsAsync() var block = acceptResult.Response?.ToObject(); var accepted = acceptResult.Error == null && block?.Hash == share.BlockHash; - if (!accepted) + if(!accepted) { logger.Warn(() => $"Block {share.BlockHeight} submission failed for pool {poolConfig.Id} because block was not found after submission"); messageBus.SendMessage(new AdminNotification($"[{share.PoolId.ToUpper()}]-[{share.Source}] Block submission failed", $"[{share.PoolId.ToUpper()}]-[{share.Source}] Block {share.BlockHeight} submission failed for pool {poolConfig.Id} because block was not found after submission")); @@ -323,7 +323,7 @@ protected virtual async Task AreDaemonsHealthyLegacyAsync() { var responses = await daemon.ExecuteCmdAllAsync(logger, BitcoinCommands.GetInfo); - if (responses.Where(x => x.Error?.InnerException?.GetType() == typeof(DaemonClientException)) + if(responses.Where(x => x.Error?.InnerException?.GetType() == typeof(DaemonClientException)) .Select(x => (DaemonClientException) x.Error.InnerException) .Any(x => x.Code == HttpStatusCode.Unauthorized)) logger.ThrowLogPoolStartupException($"Daemon reports invalid credentials"); @@ -342,18 +342,18 @@ protected virtual async Task ShowDaemonSyncProgressLegacyAsync() { var infos = await daemon.ExecuteCmdAllAsync(logger, BitcoinCommands.GetInfo); - if (infos.Length > 0) + if(infos.Length > 0) { var blockCount = infos .Max(x => x.Response?.Blocks); - if (blockCount.HasValue) + if(blockCount.HasValue) { // get list of peers and their highest block height to compare to ours var peerInfo = await daemon.ExecuteCmdAnyAsync(logger, BitcoinCommands.GetPeerInfo); var peers = peerInfo.Response; - if (peers != null && peers.Length > 0) + if(peers != null && peers.Length > 0) { var totalBlocks = peers.Max(x => x.StartingHeight); var percent = totalBlocks > 0 ? (double) blockCount / totalBlocks * 100 : 0; @@ -373,11 +373,11 @@ private async Task UpdateNetworkStatsLegacyAsync() new DaemonCmd(BitcoinCommands.GetConnectionCount) ); - if (results.Any(x => x.Error != null)) + if(results.Any(x => x.Error != null)) { var errors = results.Where(x => x.Error != null).ToArray(); - if (errors.Any()) + if(errors.Any()) logger.Warn(() => $"Error(s) refreshing network stats: {string.Join(", ", errors.Select(y => y.Error.Message))}"); } @@ -407,12 +407,12 @@ protected override void ConfigureDaemons() protected override async Task AreDaemonsHealthyAsync() { - if (hasLegacyDaemon) + if(hasLegacyDaemon) return await AreDaemonsHealthyLegacyAsync(); var responses = await daemon.ExecuteCmdAllAsync(logger, BitcoinCommands.GetBlockchainInfo); - if (responses.Where(x => x.Error?.InnerException?.GetType() == typeof(DaemonClientException)) + if(responses.Where(x => x.Error?.InnerException?.GetType() == typeof(DaemonClientException)) .Select(x => (DaemonClientException) x.Error.InnerException) .Any(x => x.Code == HttpStatusCode.Unauthorized)) logger.ThrowLogPoolStartupException($"Daemon reports invalid credentials"); @@ -422,7 +422,7 @@ protected override async Task AreDaemonsHealthyAsync() protected override async Task AreDaemonsConnectedAsync() { - if (hasLegacyDaemon) + if(hasLegacyDaemon) return await AreDaemonsConnectedLegacyAsync(); var response = await daemon.ExecuteCmdAnyAsync(logger, BitcoinCommands.GetNetworkInfo); @@ -441,13 +441,13 @@ protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) var isSynched = responses.All(x => x.Error == null); - if (isSynched) + if(isSynched) { logger.Info(() => $"All daemons synched with blockchain"); break; } - if (!syncPendingNotificationShown) + if(!syncPendingNotificationShown) { logger.Info(() => $"Daemons still syncing with network. Manager will be started once synced"); syncPendingNotificationShown = true; @@ -472,13 +472,13 @@ protected override async Task PostStartInitAsync(CancellationToken ct) var results = await daemon.ExecuteBatchAnyAsync(logger, commands); - if (results.Any(x => x.Error != null)) + if(results.Any(x => x.Error != null)) { var resultList = results.ToList(); var errors = results.Where(x => x.Error != null && commands[resultList.IndexOf(x)].Method != BitcoinCommands.SubmitBlock) .ToArray(); - if (errors.Any()) + if(errors.Any()) logger.ThrowLogPoolStartupException($"Init RPC failed: {string.Join(", ", errors.Select(y => y.Error.Message))}"); } @@ -490,7 +490,7 @@ protected override async Task PostStartInitAsync(CancellationToken ct) var difficultyResponse = results[3].Response.ToObject(); // chain detection - if (!hasLegacyDaemon) + if(!hasLegacyDaemon) network = Network.GetNetwork(blockchainInfoResponse.Chain.ToLower()); else network = daemonInfoResponse.Testnet ? Network.TestNet : Network.Main; @@ -498,19 +498,19 @@ protected override async Task PostStartInitAsync(CancellationToken ct) PostChainIdentifyConfigure(); // ensure pool owns wallet - if (validateAddressResponse == null || !validateAddressResponse.IsValid) + if(validateAddressResponse == null || !validateAddressResponse.IsValid) logger.ThrowLogPoolStartupException($"Daemon reports pool-address '{poolConfig.Address}' as invalid"); isPoS = difficultyResponse.Values().Any(x => x.Path == "proof-of-stake"); // Create pool address script from response - if (!isPoS) + if(!isPoS) poolAddressDestination = AddressToDestination(poolConfig.Address, extraPoolConfig?.AddressType); else poolAddressDestination = new PubKey(poolConfig.PubKey ?? validateAddressResponse.PubKey); // Payment-processing setup - if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) { // ensure pool owns wallet //if (!validateAddressResponse.IsMine) @@ -524,14 +524,14 @@ protected override async Task PostStartInitAsync(CancellationToken ct) BlockchainStats.RewardType = isPoS ? "POS" : "POW"; // block submission RPC method - if (submitBlockResponse.Error?.Message?.ToLower() == "method not found") + if(submitBlockResponse.Error?.Message?.ToLower() == "method not found") hasSubmitBlockMethod = false; - else if (submitBlockResponse.Error?.Code == -1) + else if(submitBlockResponse.Error?.Code == -1) hasSubmitBlockMethod = true; else logger.ThrowLogPoolStartupException($"Unable detect block submission RPC method"); - if (!hasLegacyDaemon) + if(!hasLegacyDaemon) await UpdateNetworkStatsAsync(); else await UpdateNetworkStatsLegacyAsync(); @@ -545,7 +545,7 @@ protected override async Task PostStartInitAsync(CancellationToken ct) await (!hasLegacyDaemon ? UpdateNetworkStatsAsync() : UpdateNetworkStatsLegacyAsync()); } - catch (Exception ex) + catch(Exception ex) { logger.Error(ex); } @@ -562,7 +562,7 @@ protected virtual IDestination AddressToDestination(string address, BitcoinAddre if(!addressType.HasValue) return BitcoinUtils.AddressToDestination(address, network); - switch (addressType.Value) + switch(addressType.Value) { case BitcoinAddressType.BechSegwit: return BitcoinUtils.BechSegwitAddressToDestination(poolConfig.Address, network); @@ -583,7 +583,7 @@ protected virtual void SetupCrypto() protected void ConfigureRewards() { // Donation to MiningCore development - if (network.NetworkType == NetworkType.Mainnet && + if(network.NetworkType == NetworkType.Mainnet && DevDonation.Addresses.TryGetValue(poolConfig.Template.Symbol, out var address)) { poolConfig.RewardRecipients = poolConfig.RewardRecipients.Concat(new[] @@ -609,7 +609,7 @@ public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfi extraPoolConfig = poolConfig.Extra.SafeExtensionDataAs(); extraPoolPaymentProcessingConfig = poolConfig.PaymentProcessing?.Extra?.SafeExtensionDataAs(); - if (extraPoolConfig?.MaxActiveJobs.HasValue == true) + if(extraPoolConfig?.MaxActiveJobs.HasValue == true) maxActiveJobs = extraPoolConfig.MaxActiveJobs.Value; hasLegacyDaemon = extraPoolConfig?.HasLegacyDaemon == true; diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs index b5ee06991..af61c8806 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs @@ -131,10 +131,10 @@ public virtual async Task ClassifyBlocksAsync(Block[] blocks) var block = page[j]; // check error - if (cmdResult.Error != null) + if(cmdResult.Error != null) { // Code -5 interpreted as "orphaned" - if (cmdResult.Error.Code == -5) + if(cmdResult.Error.Code == -5) { block.Status = BlockStatus.Orphaned; block.Reward = 0; @@ -148,7 +148,7 @@ public virtual async Task ClassifyBlocksAsync(Block[] blocks) } // missing transaction details are interpreted as "orphaned" - else if (transactionInfo?.Details == null || transactionInfo.Details.Length == 0) + else if(transactionInfo?.Details == null || transactionInfo.Details.Length == 0) { block.Status = BlockStatus.Orphaned; block.Reward = 0; @@ -214,19 +214,19 @@ public virtual async Task PayoutAsync(Balance[] balances) .Where(x => x.Amount > 0) .ToDictionary(x => x.Address, x => Math.Round(x.Amount, 4)); - if (amounts.Count == 0) + if(amounts.Count == 0) return; logger.Info(() => $"[{LogCategory}] Paying out {FormatAmount(balances.Sum(x => x.Amount))} to {balances.Length} addresses"); object[] args; - if (extraPoolPaymentProcessingConfig?.MinersPayTxFees == true) + if(extraPoolPaymentProcessingConfig?.MinersPayTxFees == true) { var comment = (poolConfig.PoolName ?? clusterConfig.ClusterName ?? "MiningCore").Trim() + " Payment"; var subtractFeesFrom = amounts.Keys.ToArray(); - if (!poolConfig.Template.As().HasMasterNodes) + if(!poolConfig.Template.As().HasMasterNodes) { args = new object[] { @@ -265,13 +265,13 @@ public virtual async Task PayoutAsync(Balance[] balances) var didUnlockWallet = false; - // send command - tryTransfer: + // send command + tryTransfer: var result = await daemon.ExecuteCmdSingleAsync(logger, BitcoinCommands.SendMany, args, new JsonSerializerSettings()); - if (result.Error == null) + if(result.Error == null) { - if (didUnlockWallet) + if(didUnlockWallet) { // lock wallet logger.Info(() => $"[{LogCategory}] Locking wallet"); @@ -281,7 +281,7 @@ public virtual async Task PayoutAsync(Balance[] balances) // check result var txId = result.Response; - if (string.IsNullOrEmpty(txId)) + if(string.IsNullOrEmpty(txId)) logger.Error(() => $"[{LogCategory}] {BitcoinCommands.SendMany} did not return a transaction id!"); else logger.Info(() => $"[{LogCategory}] Payout transaction id: {txId}"); @@ -293,9 +293,9 @@ public virtual async Task PayoutAsync(Balance[] balances) else { - if (result.Error.Code == (int) BitcoinRPCErrorCode.RPC_WALLET_UNLOCK_NEEDED && !didUnlockWallet) + if(result.Error.Code == (int) BitcoinRPCErrorCode.RPC_WALLET_UNLOCK_NEEDED && !didUnlockWallet) { - if (!string.IsNullOrEmpty(extraPoolPaymentProcessingConfig?.WalletPassword)) + if(!string.IsNullOrEmpty(extraPoolPaymentProcessingConfig?.WalletPassword)) { logger.Info(() => $"[{LogCategory}] Unlocking wallet"); @@ -305,7 +305,7 @@ public virtual async Task PayoutAsync(Balance[] balances) (object) 5 // unlock for N seconds }); - if (unlockResult.Error == null) + if(unlockResult.Error == null) { didUnlockWallet = true; goto tryTransfer; diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs index 0ffd38224..f5636ea61 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs @@ -67,7 +67,7 @@ protected virtual async Task OnSubscribeAsync(StratumClient client, Timestamped< { var request = tsRequest.Value; - if (request.Id == null) + if(request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); var context = client.ContextAs(); @@ -99,7 +99,7 @@ protected virtual async Task OnAuthorizeAsync(StratumClient client, Timestamped< { var request = tsRequest.Value; - if (request.Id == null) + if(request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); var context = client.ContextAs(); @@ -118,7 +118,7 @@ protected virtual async Task OnAuthorizeAsync(StratumClient client, Timestamped< context.Miner = minerName; context.Worker = workerName; - if (context.IsAuthorized) + if(context.IsAuthorized) { // respond await client.RespondAsync(context.IsAuthorized, request.Id); @@ -128,7 +128,7 @@ protected virtual async Task OnAuthorizeAsync(StratumClient client, Timestamped< // extract control vars from password var staticDiff = GetStaticDiffFromPassparts(passParts); - if (staticDiff.HasValue && + if(staticDiff.HasValue && (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty)) { @@ -162,13 +162,13 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped maxShareAge) + if(requestAge > maxShareAge) { logger.Warn(() => $"[{client.ConnectionId}] Dropping stale share submission request (server overloaded?)"); return; @@ -178,9 +178,9 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped $"[{client.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty * coin.ShareMultiplier, 3)}"); // update pool stats - if (share.IsBlockCandidate) + if(share.IsBlockCandidate) poolStats.LastPoolBlockTime = clock.Now; // update client stats @@ -239,7 +239,7 @@ private async Task OnSuggestDifficultyAsync(StratumClient client, Timestamped poolEndpoint.Difficulty) + if(requestedDiff > poolEndpoint.Difficulty) { context.SetDifficulty(requestedDiff); await client.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); @@ -264,7 +264,7 @@ private async Task OnConfigureMiningAsync(StratumClient client, Timestamped>(); var result = new Dictionary(); - foreach (var extension in extensions) + foreach(var extension in extensions) { switch(extension) { @@ -281,13 +281,13 @@ private async Task OnConfigureMiningAsync(StratumClient client, Timestamped extensionParams, Dictionary result) { //var requestedBits = extensionParams[BitcoinStratumExtensions.VersionRollingBits].Value(); uint requestedMask = BitcoinConstants.VersionRollingPoolMask; - if (extensionParams.TryGetValue(BitcoinStratumExtensions.VersionRollingMask, out var requestedMaskValue)) + if(extensionParams.TryGetValue(BitcoinStratumExtensions.VersionRollingMask, out var requestedMaskValue)) requestedMask = uint.Parse(requestedMaskValue.Value(), NumberStyles.HexNumber); // Compute effective mask @@ -300,7 +300,7 @@ private void ConfigureVersionRolling(StratumClient client, BitcoinWorkerContext logger.Info(() => $"[{client.ConnectionId}] Using version-rolling mask {result[BitcoinStratumExtensions.VersionRollingMask]}"); } - private void ConfigureMinimumDiff(StratumClient client, BitcoinWorkerContext context, + private void ConfigureMinimumDiff(StratumClient client, BitcoinWorkerContext context, Dictionary extensionParams, Dictionary result) { var requestedDiff = extensionParams[BitcoinStratumExtensions.MinimumDiffValue].Value(); @@ -308,7 +308,7 @@ private void ConfigureMinimumDiff(StratumClient client, BitcoinWorkerContext con // client may suggest higher-than-base difficulty, but not a lower one var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port]; - if (requestedDiff > poolEndpoint.Difficulty) + if(requestedDiff > poolEndpoint.Difficulty) { context.VarDiff = null; // disable vardiff context.SetDifficulty(requestedDiff); @@ -328,17 +328,17 @@ protected virtual async Task OnNewJobAsync(object jobParams) var tasks = ForEachClient(async client => { - if (!client.IsAlive) + if(!client.IsAlive) return; var context = client.ContextAs(); - if (context.IsSubscribed && context.IsAuthorized) + if(context.IsSubscribed && context.IsAuthorized) { // check alive var lastActivityAgo = clock.Now - context.LastActivity; - if (poolConfig.ClientConnectionTimeout > 0 && + if(poolConfig.ClientConnectionTimeout > 0 && lastActivityAgo.TotalSeconds > poolConfig.ClientConnectionTimeout) { logger.Info(() => $"[{client.ConnectionId}] Booting zombie-worker (idle-timeout exceeded)"); @@ -347,7 +347,7 @@ protected virtual async Task OnNewJobAsync(object jobParams) } // varDiff: if the client has a pending difficulty change, apply it now - if (context.ApplyPendingDifficulty()) + if(context.ApplyPendingDifficulty()) await client.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); // send job @@ -362,7 +362,7 @@ protected virtual async Task OnNewJobAsync(object jobParams) catch(Exception ex) { - logger.Debug(()=> $"{nameof(OnNewJobAsync)}: {ex.Message}"); + logger.Debug(() => $"{nameof(OnNewJobAsync)}: {ex.Message}"); } } @@ -394,7 +394,7 @@ protected override async Task SetupJobManager(CancellationToken ct) await manager.StartAsync(ct); - if (poolConfig.EnableInternalStratum == true) + if(poolConfig.EnableInternalStratum == true) { disposables.Add(manager.Jobs .Select(job => Observable.FromAsync(async () => @@ -500,7 +500,7 @@ protected override async Task OnVarDiffUpdateAsync(StratumClient client, double context.EnqueueNewDifficulty(newDiff); // apply immediately and notify client - if (context.HasPendingDifficulty) + if(context.HasPendingDifficulty) { context.ApplyPendingDifficulty(); diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs index 436136f43..74ad72f0c 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs @@ -49,7 +49,7 @@ public CryptonoteJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, PrepareBlobTemplate(instanceId); PrevHash = prevHash; - switch (coin.Hash) + switch(coin.Hash) { case CryptonightHashType.Normal: hashFunc = LibCryptonight.Cryptonight; @@ -100,7 +100,7 @@ private string EncodeTarget(double difficulty) var padLength = padded.Length - bytes.Length; - if (padLength > 0) + if(padLength > 0) bytes.CopyTo(padded.Slice(padLength, bytes.Length)); padded = padded.Slice(0, 4); @@ -129,7 +129,7 @@ public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out workerJob.Height = BlockTemplate.Height; workerJob.ExtraNonce = (uint) Interlocked.Increment(ref extraNonce); - if (extraNonce < 0) + if(extraNonce < 0) extraNonce = 0; blob = EncodeBlob(workerJob.ExtraNonce); @@ -145,7 +145,7 @@ public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out var context = worker.ContextAs(); // validate nonce - if (!CryptonoteConstants.RegexValidNonce.IsMatch(nonce)) + if(!CryptonoteConstants.RegexValidNonce.IsMatch(nonce)) throw new StratumException(StratumError.MinusOne, "malformed nonce"); // clone template @@ -162,22 +162,22 @@ public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out // convert var blobConverted = LibCryptonote.ConvertBlob(blob, blobTemplate.Length); - if (blobConverted == null) + if(blobConverted == null) throw new StratumException(StratumError.MinusOne, "malformed blob"); // determine variant CryptonightVariant variant = CryptonightVariant.VARIANT_0; - if (coin.HashVariant != 0) + if(coin.HashVariant != 0) variant = (CryptonightVariant) coin.HashVariant; else { - switch (coin.Hash) + switch(coin.Hash) { case CryptonightHashType.Normal: - variant = (blobConverted[0] >= 10) ? CryptonightVariant.VARIANT_4 : + variant = (blobConverted[0] >= 10) ? CryptonightVariant.VARIANT_4 : ((blobConverted[0] >= 8) ? CryptonightVariant.VARIANT_2 : - ((blobConverted[0] == 7) ? CryptonightVariant.VARIANT_1 : + ((blobConverted[0] == 7) ? CryptonightVariant.VARIANT_1 : CryptonightVariant.VARIANT_0)); break; @@ -196,7 +196,7 @@ public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out hashFunc(blobConverted, headerHash, variant, BlockTemplate.Height); var headerHashString = headerHash.ToHexString(); - if (headerHashString != workerHash) + if(headerHashString != workerHash) throw new StratumException(StratumError.MinusOne, "bad hash"); // check difficulty @@ -207,14 +207,14 @@ public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out var isBlockCandidate = shareDiff >= BlockTemplate.Difficulty; // test if share meets at least workers current difficulty - if (!isBlockCandidate && ratio < 0.99) + if(!isBlockCandidate && ratio < 0.99) { // check if share matched the previous difficulty from before a vardiff retarget - if (context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue) + if(context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue) { ratio = shareDiff / context.PreviousDifficulty.Value; - if (ratio < 0.99) + if(ratio < 0.99) throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); // use previous difficulty diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs index c0b429715..93e3d33f7 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs @@ -91,7 +91,7 @@ protected async Task UpdateJob(string via = null, string json = null) var response = string.IsNullOrEmpty(json) ? await GetBlockTemplateAsync() : GetBlockTemplateFromJson(json); // may happen if daemon is currently not connected to peers - if (response.Error != null) + if(response.Error != null) { logger.Warn(() => $"Unable to update job. Daemon responded with: {response.Error.Message} Code {response.Error.Code}"); return false; @@ -103,11 +103,11 @@ protected async Task UpdateJob(string via = null, string json = null) var isNew = job == null || newHash != job.PrevHash; - if (isNew) + if(isNew) { messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); - if (via != null) + if(via != null) logger.Info(() => $"Detected new block {blockTemplate.Height} via {via}"); else logger.Info(() => $"Detected new block {blockTemplate.Height}"); @@ -164,7 +164,7 @@ private async Task ShowDaemonSyncProgressAsync() var infos = await daemon.ExecuteCmdAllAsync(logger, CryptonoteCommands.GetInfo); var firstValidResponse = infos.FirstOrDefault(x => x.Error == null && x.Response != null)?.Response; - if (firstValidResponse != null) + if(firstValidResponse != null) { var lowestHeight = infos.Where(x => x.Error == null && x.Response != null) .Min(x => x.Response.Height); @@ -184,10 +184,10 @@ private async Task UpdateNetworkStatsAsync() { var infoResponse = await daemon.ExecuteCmdAnyAsync(logger, CryptonoteCommands.GetInfo); - if (infoResponse.Error != null) + if(infoResponse.Error != null) logger.Warn(() => $"Error(s) refreshing network stats: {infoResponse.Error.Message} (Code {infoResponse.Error.Code})"); - if (infoResponse.Response != null) + if(infoResponse.Response != null) { var info = infoResponse.Response.ToObject(); @@ -206,7 +206,7 @@ private async Task SubmitBlockAsync(Share share, string blobHex, string bl { var response = await daemon.ExecuteCmdAnyAsync(logger, CryptonoteCommands.SubmitBlock, new[] { blobHex }); - if (response.Error != null || response?.Response?.Status != "OK") + if(response.Error != null || response?.Response?.Status != "OK") { var error = response.Error?.Message ?? response.Response?.Status; @@ -237,21 +237,21 @@ public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfi .Where(x => string.IsNullOrEmpty(x.Category)) .Select(x => { - if (string.IsNullOrEmpty(x.HttpPath)) + if(string.IsNullOrEmpty(x.HttpPath)) x.HttpPath = CryptonoteConstants.DaemonRpcLocation; return x; }) .ToArray(); - if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) { // extract wallet daemon endpoints walletDaemonEndpoints = poolConfig.Daemons .Where(x => x.Category?.ToLower() == CryptonoteConstants.WalletDaemonCategory) .Select(x => { - if (string.IsNullOrEmpty(x.HttpPath)) + if(string.IsNullOrEmpty(x.HttpPath)) x.HttpPath = CryptonoteConstants.DaemonRpcLocation; // cryptonote daemons only support digest auth @@ -261,7 +261,7 @@ public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfi }) .ToArray(); - if (walletDaemonEndpoints.Length == 0) + if(walletDaemonEndpoints.Length == 0) logger.ThrowLogPoolStartupException("Wallet-RPC daemon is not configured (Daemon configuration for monero-pools require an additional entry of category \'wallet' pointing to the wallet daemon)"); } @@ -279,13 +279,13 @@ public bool ValidateAddress(string address) switch(networkType) { case CryptonoteNetworkType.Main: - if (addressPrefix != coin.AddressPrefix && + if(addressPrefix != coin.AddressPrefix && addressIntegratedPrefix != coin.AddressPrefixIntegrated) return false; break; case CryptonoteNetworkType.Test: - if (addressPrefix != coin.AddressPrefixTestnet && + if(addressPrefix != coin.AddressPrefixTestnet && addressIntegratedPrefix != coin.AddressPrefixIntegratedTestnet) return false; break; @@ -303,7 +303,7 @@ public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out var job = currentJob; - if (job != null) + if(job != null) { lock(job) { @@ -322,7 +322,7 @@ public async ValueTask SubmitShareAsync(StratumClient worker, var context = worker.ContextAs(); var job = currentJob; - if (workerJob.Height != job?.BlockTemplate.Height) + if(workerJob.Height != job?.BlockTemplate.Height) throw new StratumException(StratumError.MinusOne, "block expired"); // validate & process @@ -339,13 +339,13 @@ public async ValueTask SubmitShareAsync(StratumClient worker, share.Created = clock.Now; // if block candidate, submit & check if accepted by network - if (share.IsBlockCandidate) + if(share.IsBlockCandidate) { logger.Info(() => $"Submitting block {share.BlockHeight} [{share.BlockHash.Substring(0, 6)}]"); share.IsBlockCandidate = await SubmitBlockAsync(share, blobHex, share.BlockHash); - if (share.IsBlockCandidate) + if(share.IsBlockCandidate) { logger.Info(() => $"Daemon accepted block {share.BlockHeight} [{share.BlockHash.Substring(0, 6)}] submitted by {context.Miner}"); blockSubmissionSubject.OnNext(Unit.Default); @@ -374,7 +374,7 @@ protected override void ConfigureDaemons() daemon = new DaemonClient(jsonSerializerSettings, messageBus, clusterConfig.ClusterName ?? poolConfig.PoolName, poolConfig.Id); daemon.Configure(daemonEndpoints); - if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) { // also setup wallet daemon walletDaemon = new DaemonClient(jsonSerializerSettings, messageBus, clusterConfig.ClusterName ?? poolConfig.PoolName, poolConfig.Id); @@ -387,20 +387,20 @@ protected override async Task AreDaemonsHealthyAsync() // test daemons var responses = await daemon.ExecuteCmdAllAsync(logger, CryptonoteCommands.GetInfo); - if (responses.Where(x => x.Error?.InnerException?.GetType() == typeof(DaemonClientException)) + if(responses.Where(x => x.Error?.InnerException?.GetType() == typeof(DaemonClientException)) .Select(x => (DaemonClientException) x.Error.InnerException) .Any(x => x.Code == HttpStatusCode.Unauthorized)) logger.ThrowLogPoolStartupException($"Daemon reports invalid credentials"); - if (!responses.All(x => x.Error == null)) + if(!responses.All(x => x.Error == null)) return false; - if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) { // test wallet daemons var responses2 = await walletDaemon.ExecuteCmdAllAsync(logger, CryptonoteWalletCommands.GetAddress); - if (responses2.Where(x => x.Error?.InnerException?.GetType() == typeof(DaemonClientException)) + if(responses2.Where(x => x.Error?.InnerException?.GetType() == typeof(DaemonClientException)) .Select(x => (DaemonClientException) x.Error.InnerException) .Any(x => x.Code == HttpStatusCode.Unauthorized)) logger.ThrowLogPoolStartupException($"Wallet-Daemon reports invalid credentials"); @@ -436,13 +436,13 @@ protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) var isSynched = responses.All(x => x.Error == null || x.Error.Code != -9); - if (isSynched) + if(isSynched) { logger.Info(() => $"All daemons synched with blockchain"); break; } - if (!syncPendingNotificationShown) + if(!syncPendingNotificationShown) { logger.Info(() => $"Daemons still syncing with network. Manager will be started once synced"); syncPendingNotificationShown = true; @@ -460,15 +460,15 @@ protected override async Task PostStartInitAsync(CancellationToken ct) var coin = poolConfig.Template.As(); var infoResponse = await daemon.ExecuteCmdAnyAsync(logger, CryptonoteCommands.GetInfo); - if (infoResponse.Error != null) + if(infoResponse.Error != null) logger.ThrowLogPoolStartupException($"Init RPC failed: {infoResponse.Error.Message} (Code {infoResponse.Error.Code})"); - if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) { var addressResponse = await walletDaemon.ExecuteCmdAnyAsync(logger, ct, CryptonoteWalletCommands.GetAddress); // ensure pool owns wallet - if (clusterConfig.PaymentProcessing?.Enabled == true && addressResponse.Response?.Address != poolConfig.Address) + if(clusterConfig.PaymentProcessing?.Enabled == true && addressResponse.Response?.Address != poolConfig.Address) logger.ThrowLogPoolStartupException($"Wallet-Daemon does not own pool-address '{poolConfig.Address}'"); } @@ -479,23 +479,23 @@ protected override async Task PostStartInitAsync(CancellationToken ct) // address validation poolAddressBase58Prefix = LibCryptonote.DecodeAddress(poolConfig.Address); - if (poolAddressBase58Prefix == 0) + if(poolAddressBase58Prefix == 0) logger.ThrowLogPoolStartupException("Unable to decode pool-address"); switch(networkType) { case CryptonoteNetworkType.Main: - if (poolAddressBase58Prefix != coin.AddressPrefix) + if(poolAddressBase58Prefix != coin.AddressPrefix) logger.ThrowLogPoolStartupException($"Invalid pool address prefix. Expected {coin.AddressPrefix}, got {poolAddressBase58Prefix}"); break; case CryptonoteNetworkType.Test: - if (poolAddressBase58Prefix != coin.AddressPrefixTestnet) + if(poolAddressBase58Prefix != coin.AddressPrefixTestnet) logger.ThrowLogPoolStartupException($"Invalid pool address prefix. Expected {coin.AddressPrefix}, got {poolAddressBase58Prefix}"); break; } - if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) ConfigureRewards(); // update stats @@ -506,18 +506,18 @@ protected override async Task PostStartInitAsync(CancellationToken ct) // Periodically update network stats Observable.Interval(TimeSpan.FromMinutes(1)) - .Select(via => Observable.FromAsync(async ()=> - { - try - { - await UpdateNetworkStatsAsync(); - } - - catch (Exception ex) - { - logger.Error(ex); - } - })) + .Select(via => Observable.FromAsync(async () => + { + try + { + await UpdateNetworkStatsAsync(); + } + + catch(Exception ex) + { + logger.Error(ex); + } + })) .Concat() .Subscribe(); @@ -527,7 +527,7 @@ protected override async Task PostStartInitAsync(CancellationToken ct) private void ConfigureRewards() { // Donation to MiningCore development - if (networkType == CryptonoteNetworkType.Main && + if(networkType == CryptonoteNetworkType.Main && DevDonation.Addresses.TryGetValue(poolConfig.Template.Symbol, out var address)) { poolConfig.RewardRecipients = poolConfig.RewardRecipients.Concat(new[] @@ -552,7 +552,7 @@ protected virtual void SetupJobUpdates() blockSubmission.Select(x => ("Block-submission", (string) null)) }; - if (extraPoolConfig?.BtStream == null) + if(extraPoolConfig?.BtStream == null) { // collect ports var zmq = poolConfig.Daemons @@ -565,14 +565,14 @@ protected virtual void SetupJobUpdates() return (Socket: extra.ZmqBlockNotifySocket, Topic: topic); }); - if (zmq.Count > 0) + if(zmq.Count > 0) { logger.Info(() => $"Subscribing to ZMQ push-updates from {string.Join(", ", zmq.Values)}"); var blockNotify = daemon.ZmqSubscribe(logger, zmq) .Select(msg => { - using (msg) + using(msg) { // We just take the second frame's raw data and turn it into a hex string. // If that string changes, we got an update (DistinctUntilChanged) @@ -594,7 +594,7 @@ protected virtual void SetupJobUpdates() triggers.Add(blockNotify); } - if (poolConfig.BlockRefreshInterval > 0) + if(poolConfig.BlockRefreshInterval > 0) { // periodically update block-template var pollingInterval = poolConfig.BlockRefreshInterval > 0 ? poolConfig.BlockRefreshInterval : 1000; diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs index e13039d31..1b772cb4e 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs @@ -84,7 +84,7 @@ private async Task HandleTransferResponseAsync(DaemonResponse(); - if (response.Error == null) + if(response.Error == null) { var txHash = response.Response.TxHash; var txFee = (decimal) response.Response.Fee / coin.SmallestUnit; @@ -109,7 +109,7 @@ private async Task HandleTransferResponseAsync(DaemonResponse(); - if (response.Error == null) + if(response.Error == null) { var txHashes = response.Response.TxHashList; var txFees = response.Response.FeeList.Select(x => (decimal) x / coin.SmallestUnit).ToArray(); @@ -132,7 +132,7 @@ private async Task HandleTransferResponseAsync(DaemonResponse GetNetworkTypeAsync() { - if (!networkType.HasValue) + if(!networkType.HasValue) { var infoResponse = await daemon.ExecuteCmdAnyAsync(logger, CryptonoteCommands.GetInfo, true); var info = infoResponse.Response.ToObject(); @@ -147,7 +147,7 @@ private async Task EnsureBalance(decimal requiredAmount, CryptonoteCoinTem { var response = await walletDaemon.ExecuteCmdSingleAsync(logger, CryptonoteWalletCommands.GetBalance); - if (response.Error != null) + if(response.Error != null) { logger.Error(() => $"[{LogCategory}] Daemon command '{CryptonoteWalletCommands.GetBalance}' returned error: {response.Error.Message} code {response.Error.Code}"); return false; @@ -156,7 +156,7 @@ private async Task EnsureBalance(decimal requiredAmount, CryptonoteCoinTem var unlockedBalance = Math.Floor(response.Response.UnlockedBalance / coin.SmallestUnit); var balance = Math.Floor(response.Response.Balance / coin.SmallestUnit); - if (response.Response.UnlockedBalance < requiredAmount) + if(response.Response.UnlockedBalance < requiredAmount) { logger.Error(() => $"[{LogCategory}] Need {FormatAmount(requiredAmount)} unlocked balance, but only have {FormatAmount(unlockedBalance)} ({FormatAmount(balance)})"); return false; @@ -171,7 +171,7 @@ private async Task PayoutBatch(Balance[] balances) var coin = poolConfig.Template.As(); // ensure there's enough balance - if (!await EnsureBalance(balances.Sum(x => x.Amount), coin)) + if(!await EnsureBalance(balances.Sum(x => x.Amount), coin)) return false; // build request @@ -193,7 +193,7 @@ private async Task PayoutBatch(Balance[] balances) GetTxKey = true }; - if (request.Destinations.Length == 0) + if(request.Destinations.Length == 0) return true; logger.Info(() => $"[{LogCategory}] Paying out {FormatAmount(balances.Sum(x => x.Amount))} to {balances.Length} addresses:\n{string.Join("\n", balances.OrderByDescending(x => x.Amount).Select(x => $"{FormatAmount(x.Amount)} to {x.Address}"))}"); @@ -202,9 +202,9 @@ private async Task PayoutBatch(Balance[] balances) var transferResponse = await walletDaemon.ExecuteCmdSingleAsync(logger, CryptonoteWalletCommands.Transfer, request); // gracefully handle error -4 (transaction would be too large. try /transfer_split) - if (transferResponse.Error?.Code == -4) + if(transferResponse.Error?.Code == -4) { - if (walletSupportsTransferSplit) + if(walletSupportsTransferSplit) { logger.Error(() => $"[{LogCategory}] Daemon command '{CryptonoteWalletCommands.Transfer}' returned error: {transferResponse.Error.Message} code {transferResponse.Error.Code}"); logger.Info(() => $"[{LogCategory}] Retrying transfer using {CryptonoteWalletCommands.TransferSplit}"); @@ -223,16 +223,16 @@ private void ExtractAddressAndPaymentId(string input, out string address, out st paymentId = null; var index = input.IndexOf(PayoutConstants.PayoutInfoSeperator); - if (index != -1) + if(index != -1) { address = input.Substring(0, index); - if (index + 1 < input.Length) + if(index + 1 < input.Length) { paymentId = input.Substring(index + 1); // ignore invalid payment ids - if (paymentId.Length != CryptonoteConstants.PaymentIdHexLength) + if(paymentId.Length != CryptonoteConstants.PaymentIdHexLength) paymentId = null; } } @@ -249,7 +249,7 @@ private async Task PayoutToPaymentId(Balance balance) var isIntegratedAddress = string.IsNullOrEmpty(paymentId); // ensure there's enough balance - if (!await EnsureBalance(balance.Amount, coin)) + if(!await EnsureBalance(balance.Amount, coin)) return false; // build request @@ -267,10 +267,10 @@ private async Task PayoutToPaymentId(Balance balance) GetTxKey = true }; - if (!isIntegratedAddress) + if(!isIntegratedAddress) request.PaymentId = paymentId; - if (!isIntegratedAddress) + if(!isIntegratedAddress) logger.Info(() => $"[{LogCategory}] Paying out {FormatAmount(balance.Amount)} to address {balance.Address} with paymentId {paymentId}"); else logger.Info(() => $"[{LogCategory}] Paying out {FormatAmount(balance.Amount)} to integrated address {balance.Address}"); @@ -278,10 +278,10 @@ private async Task PayoutToPaymentId(Balance balance) // send command var result = await walletDaemon.ExecuteCmdSingleAsync(logger, CryptonoteWalletCommands.Transfer, request); - if (walletSupportsTransferSplit) + if(walletSupportsTransferSplit) { // gracefully handle error -4 (transaction would be too large. try /transfer_split) - if (result.Error?.Code == -4) + if(result.Error?.Code == -4) { logger.Info(() => $"[{LogCategory}] Retrying transfer using {CryptonoteWalletCommands.TransferSplit}"); @@ -311,7 +311,7 @@ public async Task ConfigureAsync(ClusterConfig clusterConfig, PoolConfig poolCon .Where(x => string.IsNullOrEmpty(x.Category)) .Select(x => { - if (string.IsNullOrEmpty(x.HttpPath)) + if(string.IsNullOrEmpty(x.HttpPath)) x.HttpPath = CryptonoteConstants.DaemonRpcLocation; return x; @@ -326,7 +326,7 @@ public async Task ConfigureAsync(ClusterConfig clusterConfig, PoolConfig poolCon .Where(x => x.Category?.ToLower() == CryptonoteConstants.WalletDaemonCategory) .Select(x => { - if (string.IsNullOrEmpty(x.HttpPath)) + if(string.IsNullOrEmpty(x.HttpPath)) x.HttpPath = CryptonoteConstants.DaemonRpcLocation; return x; @@ -374,13 +374,13 @@ public async Task ClassifyBlocksAsync(Block[] blocks) Height = block.BlockHeight }); - if (rpcResult.Error != null) + if(rpcResult.Error != null) { logger.Debug(() => $"[{LogCategory}] Daemon reports error '{rpcResult.Error.Message}' (Code {rpcResult.Error.Code}) for block {block.BlockHeight}"); continue; } - if (rpcResult.Response?.BlockHeader == null) + if(rpcResult.Response?.BlockHeader == null) { logger.Debug(() => $"[{LogCategory}] Daemon returned no header for block {block.BlockHeight}"); continue; @@ -395,7 +395,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); // orphaned? - if (blockHeader.IsOrphaned || blockHeader.Hash != block.TransactionConfirmationData) + if(blockHeader.IsOrphaned || blockHeader.Hash != block.TransactionConfirmationData) { block.Status = BlockStatus.Orphaned; block.Reward = 0; @@ -405,7 +405,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) } // matured and spendable? - if (blockHeader.Depth >= CryptonoteConstants.PayoutMinBlockConfirmations) + if(blockHeader.Depth >= CryptonoteConstants.PayoutMinBlockConfirmations) { block.Status = BlockStatus.Confirmed; block.ConfirmationProgress = 1; @@ -465,7 +465,7 @@ public async Task PayoutAsync(Balance[] balances) switch(networkType) { case CryptonoteNetworkType.Main: - if (addressPrefix != coin.AddressPrefix && + if(addressPrefix != coin.AddressPrefix && addressIntegratedPrefix != coin.AddressPrefixIntegrated) { logger.Warn(() => $"[{LogCategory}] Excluding payment to invalid address {x.Address}"); @@ -475,7 +475,7 @@ public async Task PayoutAsync(Balance[] balances) break; case CryptonoteNetworkType.Test: - if (addressPrefix != coin.AddressPrefixTestnet && + if(addressPrefix != coin.AddressPrefixTestnet && addressIntegratedPrefix != coin.AddressPrefixIntegratedTestnet) { logger.Warn(() => $"[{LogCategory}] Excluding payment to invalid address {x.Address}"); @@ -502,22 +502,22 @@ public async Task PayoutAsync(Balance[] balances) switch(networkType) { case CryptonoteNetworkType.Main: - if (addressIntegratedPrefix == coin.AddressPrefixIntegrated) + if(addressIntegratedPrefix == coin.AddressPrefixIntegrated) isIntegratedAddress = true; break; case CryptonoteNetworkType.Test: - if (addressIntegratedPrefix == coin.AddressPrefixIntegratedTestnet) + if(addressIntegratedPrefix == coin.AddressPrefixIntegratedTestnet) isIntegratedAddress = true; break; } return !hasPaymentId && !isIntegratedAddress; }) - .OrderByDescending(x=> x.Amount) + .OrderByDescending(x => x.Amount) .ToArray(); - if (simpleBalances.Length > 0) + if(simpleBalances.Length > 0) #if false await PayoutBatch(simpleBalances); #else @@ -533,7 +533,7 @@ public async Task PayoutAsync(Balance[] balances) .Take(pageSize) .ToArray(); - if (!await PayoutBatch(page)) + if(!await PayoutBatch(page)) break; } } @@ -545,7 +545,7 @@ public async Task PayoutAsync(Balance[] balances) .Where(x => x.Amount >= minimumPaymentToPaymentId) .ToArray(); - foreach (var balance in paymentIdBalances) + foreach(var balance in paymentIdBalances) { if(!await PayoutToPaymentId(balance)) break; diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs index 26251c0b2..291c468f7 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs @@ -66,12 +66,12 @@ private async Task OnLoginAsync(StratumClient client, Timestamped(); - if (request.Id == null) + if(request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); var loginRequest = request.ParamsAs(); - if (string.IsNullOrEmpty(loginRequest?.Login)) + if(string.IsNullOrEmpty(loginRequest?.Login)) throw new StratumException(StratumError.MinusOne, "missing login"); // extract worker/miner/paymentid @@ -84,12 +84,12 @@ private async Task OnLoginAsync(StratumClient client, Timestamped= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty)) { @@ -139,13 +139,13 @@ private async Task OnGetJobAsync(StratumClient client, Timestamped(); - if (request.Id == null) + if(request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); var getJobRequest = request.ParamsAs(); // validate worker - if (client.ConnectionId != getJobRequest?.WorkerId || !context.IsAuthorized) + if(client.ConnectionId != getJobRequest?.WorkerId || !context.IsAuthorized) throw new StratumException(StratumError.MinusOne, "unauthorized"); // respond @@ -161,7 +161,7 @@ private CryptonoteJobParams CreateWorkerJob(StratumClient client) manager.PrepareWorkerJob(job, out var blob, out var target); // should never happen - if (string.IsNullOrEmpty(blob) || string.IsNullOrEmpty(blob)) + if(string.IsNullOrEmpty(blob) || string.IsNullOrEmpty(blob)) return null; var result = new CryptonoteJobParams @@ -188,13 +188,13 @@ private async Task OnSubmitAsync(StratumClient client, Timestamped maxShareAge) + if(requestAge > maxShareAge) { logger.Warn(() => $"[{client.ConnectionId}] Dropping stale share submission request (server overloaded?)"); return; @@ -204,7 +204,7 @@ private async Task OnSubmitAsync(StratumClient client, Timestamped(); // validate worker - if (client.ConnectionId != submitRequest?.WorkerId || !context.IsAuthorized) + if(client.ConnectionId != submitRequest?.WorkerId || !context.IsAuthorized) throw new StratumException(StratumError.MinusOne, "unauthorized"); // recognize activity @@ -216,7 +216,7 @@ private async Task OnSubmitAsync(StratumClient client, Timestamped $"[{client.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty, 3)}"); // update pool stats - if (share.IsBlockCandidate) + if(share.IsBlockCandidate) poolStats.LastPoolBlockTime = clock.Now; // update client stats @@ -280,17 +280,17 @@ private Task OnNewJobAsync() var tasks = ForEachClient(async client => { - if (!client.IsAlive) + if(!client.IsAlive) return; var context = client.ContextAs(); - if (context.IsSubscribed && context.IsAuthorized) + if(context.IsSubscribed && context.IsAuthorized) { // check alive var lastActivityAgo = clock.Now - context.LastActivity; - if (poolConfig.ClientConnectionTimeout > 0 && + if(poolConfig.ClientConnectionTimeout > 0 && lastActivityAgo.TotalSeconds > poolConfig.ClientConnectionTimeout) { logger.Info(() => $"[[{client.ConnectionId}] Booting zombie-worker (idle-timeout exceeded)"); @@ -305,7 +305,7 @@ private Task OnNewJobAsync() }); return Task.WhenAll(tasks); - } + } #region Overrides @@ -316,7 +316,7 @@ protected override async Task SetupJobManager(CancellationToken ct) await manager.StartAsync(ct); - if (poolConfig.EnableInternalStratum == true) + if(poolConfig.EnableInternalStratum == true) { disposables.Add(manager.Blocks .Select(_ => Observable.FromAsync(async () => @@ -326,7 +326,7 @@ protected override async Task SetupJobManager(CancellationToken ct) await OnNewJobAsync(); } - catch (Exception ex) + catch(Exception ex) { logger.Debug(() => $"{nameof(OnNewJobAsync)}: {ex.Message}"); } @@ -414,7 +414,7 @@ protected override async Task OnVarDiffUpdateAsync(StratumClient client, double // apply immediately and notify client var context = client.ContextAs(); - if (context.HasPendingDifficulty) + if(context.HasPendingDifficulty) { context.ApplyPendingDifficulty(); diff --git a/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/TransferResponse.cs b/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/TransferResponse.cs index a7470ddca..0d91e24ce 100644 --- a/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/TransferResponse.cs +++ b/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/TransferResponse.cs @@ -52,7 +52,7 @@ public class TransferResponse /// [JsonProperty("do_not_relay")] public string DoNotRelay { get; set; } - + public string Status { get; set; } } } diff --git a/src/Miningcore/Blockchain/Equihash/Custom/BitcoinGold/BitcoinGoldJob.cs b/src/Miningcore/Blockchain/Equihash/Custom/BitcoinGold/BitcoinGoldJob.cs index d9b0d2284..a3c9df44a 100644 --- a/src/Miningcore/Blockchain/Equihash/Custom/BitcoinGold/BitcoinGoldJob.cs +++ b/src/Miningcore/Blockchain/Equihash/Custom/BitcoinGold/BitcoinGoldJob.cs @@ -57,12 +57,12 @@ protected override Transaction CreateOutputTransaction() protected override void BuildCoinbase() { - var script = TxIn.CreateCoinbase((int)BlockTemplate.Height).ScriptSig; + var script = TxIn.CreateCoinbase((int) BlockTemplate.Height).ScriptSig; // output transaction txOut = CreateOutputTransaction(); - using (var stream = new MemoryStream()) + using(var stream = new MemoryStream()) { var bs = new BitcoinStream(stream, true); @@ -94,11 +94,11 @@ private byte[] SerializeOutputTransaction(Transaction tx) { var withDefaultWitnessCommitment = !string.IsNullOrEmpty(BlockTemplate.DefaultWitnessCommitment); - var outputCount = (uint)tx.Outputs.Count; - if (withDefaultWitnessCommitment) + var outputCount = (uint) tx.Outputs.Count; + if(withDefaultWitnessCommitment) outputCount++; - using (var stream = new MemoryStream()) + using(var stream = new MemoryStream()) { var bs = new BitcoinStream(stream, true); @@ -110,11 +110,11 @@ private byte[] SerializeOutputTransaction(Transaction tx) uint rawLength; // serialize witness (segwit) - if (withDefaultWitnessCommitment) + if(withDefaultWitnessCommitment) { amount = 0; raw = BlockTemplate.DefaultWitnessCommitment.HexToByteArray(); - rawLength = (uint)raw.Length; + rawLength = (uint) raw.Length; bs.ReadWrite(ref amount); bs.ReadWriteAsVarInt(ref rawLength); @@ -122,12 +122,12 @@ private byte[] SerializeOutputTransaction(Transaction tx) } // serialize outputs - foreach (var output in tx.Outputs) + foreach(var output in tx.Outputs) { amount = output.Value.Satoshi; var outScript = output.ScriptPubKey; raw = outScript.ToBytes(true); - rawLength = (uint)raw.Length; + rawLength = (uint) raw.Length; bs.ReadWrite(ref amount); bs.ReadWriteAsVarInt(ref rawLength); @@ -146,7 +146,7 @@ protected override byte[] SerializeHeader(uint nTime, string nonce) var blockHeader = new EquihashBlockHeader { - Version = (int)BlockTemplate.Version, + Version = (int) BlockTemplate.Version, Bits = new Target(Encoders.Hex.DecodeData(BlockTemplate.Bits)), HashPrevBlock = uint256.Parse(BlockTemplate.PreviousBlockhash), HashMerkleRoot = new uint256(merkleRoot), @@ -178,11 +178,11 @@ public override void Init(EquihashBlockTemplate blockTemplate, string jobId, chainConfig = coin.GetNetwork(network.NetworkType); BlockTemplate = blockTemplate; JobId = jobId; - Difficulty = (double)new BigRational(chainConfig.Diff1BValue, BlockTemplate.Target.HexToReverseByteArray().AsSpan().ToBigInteger()); + Difficulty = (double) new BigRational(chainConfig.Diff1BValue, BlockTemplate.Target.HexToReverseByteArray().AsSpan().ToBigInteger()); this.solver = solver; - if (!string.IsNullOrEmpty(BlockTemplate.Target)) + if(!string.IsNullOrEmpty(BlockTemplate.Target)) blockTargetValue = new uint256(BlockTemplate.Target); else { diff --git a/src/Miningcore/Blockchain/Equihash/Custom/Minexcoin/MinexcoinJob.cs b/src/Miningcore/Blockchain/Equihash/Custom/Minexcoin/MinexcoinJob.cs index e069e4bac..c423d9559 100644 --- a/src/Miningcore/Blockchain/Equihash/Custom/Minexcoin/MinexcoinJob.cs +++ b/src/Miningcore/Blockchain/Equihash/Custom/Minexcoin/MinexcoinJob.cs @@ -52,7 +52,7 @@ protected override Transaction CreateOutputTransaction() private Money ComputeBankReward(uint blockHeight, Money totalReward) { - if (blockHeight <= 4500000) + if(blockHeight <= 4500000) { /** * 1- 900000 20% diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJob.cs b/src/Miningcore/Blockchain/Equihash/EquihashJob.cs index e1019ed70..a6c62a6ad 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJob.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJob.cs @@ -94,19 +94,19 @@ protected virtual Transaction CreateOutputTransaction() // set versions tx.Version = txVersion; - if (isOverwinterActive) + if(isOverwinterActive) { overwinterField.SetValue(tx, true); versionGroupField.SetValue(tx, txVersionGroupId); } // calculate outputs - if (chainConfig.PayFoundersReward && + if(chainConfig.PayFoundersReward && (chainConfig.LastFoundersRewardBlockHeight >= BlockTemplate.Height || chainConfig.TreasuryRewardStartBlockHeight > 0)) { // founders or treasury reward? - if (chainConfig.TreasuryRewardStartBlockHeight > 0 && + if(chainConfig.TreasuryRewardStartBlockHeight > 0 && BlockTemplate.Height >= chainConfig.TreasuryRewardStartBlockHeight) { // pool reward (t-addr) @@ -145,7 +145,7 @@ protected virtual Transaction CreateOutputTransaction() private string GetTreasuryRewardAddress() { - var index = (int)Math.Floor((BlockTemplate.Height - chainConfig.TreasuryRewardStartBlockHeight) / + var index = (int) Math.Floor((BlockTemplate.Height - chainConfig.TreasuryRewardStartBlockHeight) / chainConfig.TreasuryRewardAddressChangeInterval % chainConfig.TreasuryRewardAddresses.Length); var address = chainConfig.TreasuryRewardAddresses[index]; @@ -176,7 +176,7 @@ protected virtual byte[] SerializeHeader(uint nTime, string nonce) { var blockHeader = new EquihashBlockHeader { - Version = (int)BlockTemplate.Version, + Version = (int) BlockTemplate.Version, Bits = new Target(Encoders.Hex.DecodeData(BlockTemplate.Bits)), HashPrevBlock = uint256.Parse(BlockTemplate.PreviousBlockhash), HashMerkleRoot = new uint256(merkleRoot), @@ -184,7 +184,7 @@ protected virtual byte[] SerializeHeader(uint nTime, string nonce) Nonce = nonce }; - if (isSaplingActive && !string.IsNullOrEmpty(BlockTemplate.FinalSaplingRootHash)) + if(isSaplingActive && !string.IsNullOrEmpty(BlockTemplate.FinalSaplingRootHash)) blockHeader.HashReserved = BlockTemplate.FinalSaplingRootHash.HexToReverseByteArray(); return blockHeader.ToBytes(); @@ -192,9 +192,9 @@ protected virtual byte[] SerializeHeader(uint nTime, string nonce) private byte[] BuildRawTransactionBuffer() { - using (var stream = new MemoryStream()) + using(var stream = new MemoryStream()) { - foreach (var tx in BlockTemplate.Transactions) + foreach(var tx in BlockTemplate.Transactions) { var txRaw = tx.Data.HexToByteArray(); stream.Write(txRaw); @@ -206,10 +206,10 @@ private byte[] BuildRawTransactionBuffer() private byte[] SerializeBlock(Span header, Span coinbase, Span solution) { - var transactionCount = (uint)BlockTemplate.Transactions.Length + 1; // +1 for prepended coinbase tx + var transactionCount = (uint) BlockTemplate.Transactions.Length + 1; // +1 for prepended coinbase tx var rawTransactionBuffer = BuildRawTransactionBuffer(); - using (var stream = new MemoryStream()) + using(var stream = new MemoryStream()) { var bs = new BitcoinStream(stream, true); @@ -233,7 +233,7 @@ private byte[] SerializeBlock(Span header, Span coinbase, Span var headerBytes = SerializeHeader(nTime, nonce); // verify solution - if (!solver.Verify(headerBytes, solutionBytes.Slice(chainConfig.SolutionPreambleSize))) + if(!solver.Verify(headerBytes, solutionBytes.Slice(chainConfig.SolutionPreambleSize))) throw new StratumException(StratumError.Other, "invalid solution"); // concat header and solution @@ -243,11 +243,11 @@ private byte[] SerializeBlock(Span header, Span coinbase, Span // hash block-header Span headerHash = stackalloc byte[32]; - headerHasher.Digest(headerSolutionBytes, headerHash, (ulong)nTime); + headerHasher.Digest(headerSolutionBytes, headerHash, (ulong) nTime); var headerValue = new uint256(headerHash); // calc share-diff - var shareDiff = (double)new BigRational(chainConfig.Diff1BValue, headerHash.ToBigInteger()); + var shareDiff = (double) new BigRational(chainConfig.Diff1BValue, headerHash.ToBigInteger()); var stratumDifficulty = context.Difficulty; var ratio = shareDiff / stratumDifficulty; @@ -255,14 +255,14 @@ private byte[] SerializeBlock(Span header, Span coinbase, Span var isBlockCandidate = headerValue <= blockTargetValue; // test if share meets at least workers current difficulty - if (!isBlockCandidate && ratio < 0.99) + if(!isBlockCandidate && ratio < 0.99) { // check if share matched the previous difficulty from before a vardiff retarget - if (context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue) + if(context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue) { ratio = shareDiff / context.PreviousDifficulty.Value; - if (ratio < 0.99) + if(ratio < 0.99) throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); // use previous difficulty @@ -280,7 +280,7 @@ private byte[] SerializeBlock(Span header, Span coinbase, Span Difficulty = stratumDifficulty, }; - if (isBlockCandidate) + if(isBlockCandidate) { var headerHashReversed = headerHash.ToNewReverseArray(); @@ -299,10 +299,10 @@ private byte[] SerializeBlock(Span header, Span coinbase, Span private bool RegisterSubmit(string nonce, string solution) { - lock (submissions) + lock(submissions) { var key = nonce.ToLower() + solution.ToLower(); - if (submissions.Contains(key)) + if(submissions.Contains(key)) return false; submissions.Add(key); @@ -348,13 +348,13 @@ public virtual void Init(EquihashBlockTemplate blockTemplate, string jobId, chainConfig.OverwinterActivationHeight.Value > 0 && blockTemplate.Height >= chainConfig.OverwinterActivationHeight.Value; - if (isSaplingActive) + if(isSaplingActive) { txVersion = chainConfig.SaplingTxVersion.Value; txVersionGroupId = chainConfig.SaplingTxVersionGroupId.Value; } - else if (isOverwinterActive) + else if(isOverwinterActive) { txVersion = chainConfig.OverwinterTxVersion.Value; txVersionGroupId = chainConfig.OverwinterTxVersionGroupId.Value; @@ -363,7 +363,7 @@ public virtual void Init(EquihashBlockTemplate blockTemplate, string jobId, // Misc this.solver = solver; - if (!string.IsNullOrEmpty(BlockTemplate.Target)) + if(!string.IsNullOrEmpty(BlockTemplate.Target)) blockTargetValue = new uint256(BlockTemplate.Target); else { @@ -376,16 +376,16 @@ public virtual void Init(EquihashBlockTemplate blockTemplate, string jobId, .ReverseInPlace() .ToHexString(); - if (blockTemplate.Subsidy != null) + if(blockTemplate.Subsidy != null) blockReward = blockTemplate.Subsidy.Miner * BitcoinConstants.SatoshisPerBitcoin; else blockReward = BlockTemplate.CoinbaseValue; - if (chainConfig?.PayFoundersReward == true) + if(chainConfig?.PayFoundersReward == true) { var founders = blockTemplate.Subsidy.Founders ?? blockTemplate.Subsidy.Community; - if (!founders.HasValue) + if(!founders.HasValue) throw new Exception("Error, founders reward missing for block template"); blockReward = (blockTemplate.Subsidy.Miner + founders.Value) * BitcoinConstants.SatoshisPerBitcoin; @@ -437,25 +437,25 @@ public virtual void Init(EquihashBlockTemplate blockTemplate, string jobId, var context = worker.ContextAs(); // validate nTime - if (nTime.Length != 8) + if(nTime.Length != 8) throw new StratumException(StratumError.Other, "incorrect size of ntime"); var nTimeInt = uint.Parse(nTime.HexToReverseByteArray().ToHexString(), NumberStyles.HexNumber); - if (nTimeInt < BlockTemplate.CurTime || nTimeInt > ((DateTimeOffset)clock.Now).ToUnixTimeSeconds() + 7200) + if(nTimeInt < BlockTemplate.CurTime || nTimeInt > ((DateTimeOffset) clock.Now).ToUnixTimeSeconds() + 7200) throw new StratumException(StratumError.Other, "ntime out of range"); var nonce = context.ExtraNonce1 + extraNonce2; // validate nonce - if (nonce.Length != 64) + if(nonce.Length != 64) throw new StratumException(StratumError.Other, "incorrect size of extraNonce2"); // validate solution - if (solution.Length != (chainConfig.SolutionSize + chainConfig.SolutionPreambleSize) * 2) + if(solution.Length != (chainConfig.SolutionSize + chainConfig.SolutionPreambleSize) * 2) throw new StratumException(StratumError.Other, "incorrect size of solution"); // dupe check - if (!RegisterSubmit(nonce, solution)) + if(!RegisterSubmit(nonce, solution)) throw new StratumException(StratumError.DuplicateShare, "duplicate share"); return ProcessShareInternal(worker, nonce, nTimeInt, solution); diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index eea887391..66655e20b 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -64,7 +64,7 @@ private async Task> GetBlockTemplateAsync( var result = await daemon.ExecuteCmdAnyAsync(logger, BitcoinCommands.GetBlockTemplate, getBlockTemplateParams); - if (subsidyResponse.Error == null && result.Error == null && result.Response != null) + if(subsidyResponse.Error == null && result.Error == null && result.Response != null) result.Response.Subsidy = subsidyResponse.Response; else if(subsidyResponse.Error?.Code != (int) BitcoinRPCErrorCode.RPC_METHOD_NOT_FOUND) result.Error = new JsonRpcException(-1, $"{BitcoinCommands.GetBlockSubsidy} failed", null); @@ -86,7 +86,7 @@ private DaemonResponse GetBlockTemplateFromJson(string js protected override IDestination AddressToDestination(string address, BitcoinAddressType? addressType) { - if (!coin.UsesZCashAddressFormat) + if(!coin.UsesZCashAddressFormat) return base.AddressToDestination(address, addressType); var decoded = Encoders.Base58.DecodeData(address); @@ -115,13 +115,13 @@ private EquihashJob CreateJob() try { - if (forceUpdate) + if(forceUpdate) lastJobRebroadcast = clock.Now; var response = string.IsNullOrEmpty(json) ? await GetBlockTemplateAsync() : GetBlockTemplateFromJson(json); // may happen if daemon is currently not connected to peers - if (response.Error != null) + if(response.Error != null) { logger.Warn(() => $"Unable to update job. Daemon responded with: {response.Error.Message} Code {response.Error.Code}"); return (false, forceUpdate); @@ -135,10 +135,10 @@ private EquihashJob CreateJob() job.BlockTemplate?.PreviousBlockhash != blockTemplate.PreviousBlockhash && blockTemplate.Height > job.BlockTemplate?.Height); - if (isNew) + if(isNew) messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); - if (isNew || forceUpdate) + if(isNew || forceUpdate) { job = CreateJob(); @@ -146,11 +146,11 @@ private EquihashJob CreateJob() poolConfig, clusterConfig, clock, poolAddressDestination, network, solver); - lock (jobLock) + lock(jobLock) { - if (isNew) + if(isNew) { - if (via != null) + if(via != null) logger.Info(() => $"Detected new block {blockTemplate.Height} via {via}"); else logger.Info(() => $"Detected new block {blockTemplate.Height}"); @@ -166,7 +166,7 @@ private EquihashJob CreateJob() validJobs.Insert(0, job); // trim active jobs - while (validJobs.Count > maxActiveJobs) + while(validJobs.Count > maxActiveJobs) validJobs.RemoveAt(validJobs.Count - 1); } @@ -176,7 +176,7 @@ private EquihashJob CreateJob() return (isNew, forceUpdate); } - catch (Exception ex) + catch(Exception ex) { logger.Error(ex, () => $"Error during {nameof(UpdateJob)}"); } @@ -204,7 +204,7 @@ public override async Task ValidateAddressAsync(string address, Cancellati Contract.Requires(!string.IsNullOrEmpty(address), $"{nameof(address)} must not be empty"); // handle t-addr - if (await base.ValidateAddressAsync(address, ct)) + if(await base.ValidateAddressAsync(address, ct)) return true; // handle z-addr @@ -240,7 +240,7 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob logger.LogInvoke(new[] { worker.ConnectionId }); - if (!(submission is object[] submitParams)) + if(!(submission is object[] submitParams)) throw new StratumException(StratumError.Other, "invalid params"); var context = worker.ContextAs(); @@ -252,10 +252,10 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob var extraNonce2 = submitParams[3] as string; var solution = submitParams[4] as string; - if (string.IsNullOrEmpty(workerValue)) + if(string.IsNullOrEmpty(workerValue)) throw new StratumException(StratumError.Other, "missing or invalid workername"); - if (string.IsNullOrEmpty(solution)) + if(string.IsNullOrEmpty(solution)) throw new StratumException(StratumError.Other, "missing or invalid solution"); EquihashJob job; @@ -265,7 +265,7 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob job = validJobs.FirstOrDefault(x => x.JobId == jobId); } - if (job == null) + if(job == null) throw new StratumException(StratumError.JobNotFound, "job not found"); // extract worker/miner/payoutid @@ -277,7 +277,7 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob var (share, blockHex) = job.ProcessShare(worker, extraNonce2, nTime, solution); // if block candidate, submit & check if accepted by network - if (share.IsBlockCandidate) + if(share.IsBlockCandidate) { logger.Info(() => $"Submitting block {share.BlockHeight} [{share.BlockHash}]"); @@ -286,7 +286,7 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob // is it still a block candidate? share.IsBlockCandidate = acceptResponse.Accepted; - if (share.IsBlockCandidate) + if(share.IsBlockCandidate) { logger.Info(() => $"Daemon accepted block {share.BlockHeight} [{share.BlockHash}] submitted by {minerName}"); diff --git a/src/Miningcore/Blockchain/Equihash/EquihashPayoutHandler.cs b/src/Miningcore/Blockchain/Equihash/EquihashPayoutHandler.cs index 82c47217e..2375e9f08 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashPayoutHandler.cs @@ -92,7 +92,7 @@ public override async Task PayoutAsync(Balance[] balances) Contract.RequiresNonNull(balances, nameof(balances)); // Shield first - if (supportsNativeShielding) + if(supportsNativeShielding) await ShieldCoinbaseAsync(); else await ShieldCoinbaseEmulatedAsync(); @@ -119,7 +119,7 @@ public override async Task PayoutAsync(Balance[] balances) .Select(x => new ZSendManyRecipient { Address = x.Address, Amount = Math.Round(x.Amount, 8) }) .ToList(); - if (amounts.Count == 0) + if(amounts.Count == 0) return; var pageAmount = amounts.Sum(x => x.Amount); @@ -131,7 +131,7 @@ public override async Task PayoutAsync(Balance[] balances) ZMinConfirmations, // only spend funds covered by this many confirmations }); - if (balanceResult.Error != null || (decimal) (double) balanceResult.Response - TransferFee < pageAmount) + if(balanceResult.Error != null || (decimal) (double) balanceResult.Response - TransferFee < pageAmount) { logger.Info(() => $"[{LogCategory}] Insufficient shielded balance for payment of {FormatAmount(pageAmount)}"); return; @@ -147,16 +147,16 @@ public override async Task PayoutAsync(Balance[] balances) TransferFee }; - // send command - tryTransfer: + // send command + tryTransfer: var result = await daemon.ExecuteCmdSingleAsync(logger, EquihashCommands.ZSendMany, args); - if (result.Error == null) + if(result.Error == null) { var operationId = result.Response; // check result - if (string.IsNullOrEmpty(operationId)) + if(string.IsNullOrEmpty(operationId)) logger.Error(() => $"[{LogCategory}] {EquihashCommands.ZSendMany} did not return a operation id!"); else { @@ -169,12 +169,12 @@ public override async Task PayoutAsync(Balance[] balances) var operationResultResponse = await daemon.ExecuteCmdSingleAsync(logger, EquihashCommands.ZGetOperationResult, new object[] { new object[] { operationId } }); - if (operationResultResponse.Error == null && + if(operationResultResponse.Error == null && operationResultResponse.Response?.Any(x => x.OperationId == operationId) == true) { var operationResult = operationResultResponse.Response.First(x => x.OperationId == operationId); - if (!Enum.TryParse(operationResult.Status, true, out ZOperationStatus status)) + if(!Enum.TryParse(operationResult.Status, true, out ZOperationStatus status)) { logger.Error(() => $"Unrecognized operation status: {operationResult.Status}"); break; @@ -210,9 +210,9 @@ public override async Task PayoutAsync(Balance[] balances) else { - if (result.Error.Code == (int) BitcoinRPCErrorCode.RPC_WALLET_UNLOCK_NEEDED && !didUnlockWallet) + if(result.Error.Code == (int) BitcoinRPCErrorCode.RPC_WALLET_UNLOCK_NEEDED && !didUnlockWallet) { - if (!string.IsNullOrEmpty(extraPoolPaymentProcessingConfig?.WalletPassword)) + if(!string.IsNullOrEmpty(extraPoolPaymentProcessingConfig?.WalletPassword)) { logger.Info(() => $"[{LogCategory}] Unlocking wallet"); @@ -222,7 +222,7 @@ public override async Task PayoutAsync(Balance[] balances) (object) 5 // unlock for N seconds }); - if (unlockResult.Error == null) + if(unlockResult.Error == null) { didUnlockWallet = true; goto tryTransfer; @@ -277,9 +277,9 @@ private async Task ShieldCoinbaseAsync() var result = await daemon.ExecuteCmdSingleAsync(logger, EquihashCommands.ZShieldCoinbase, args); - if (result.Error != null) + if(result.Error != null) { - if (result.Error.Code == -6) + if(result.Error.Code == -6) logger.Info(() => $"[{LogCategory}] No funds to shield"); else logger.Error(() => $"[{LogCategory}] {EquihashCommands.ZShieldCoinbase} returned error: {result.Error.Message} code {result.Error.Code}"); @@ -298,12 +298,12 @@ private async Task ShieldCoinbaseAsync() var operationResultResponse = await daemon.ExecuteCmdSingleAsync(logger, EquihashCommands.ZGetOperationResult, new object[] { new object[] { operationId } }); - if (operationResultResponse.Error == null && + if(operationResultResponse.Error == null && operationResultResponse.Response?.Any(x => x.OperationId == operationId) == true) { var operationResult = operationResultResponse.Response.First(x => x.OperationId == operationId); - if (!Enum.TryParse(operationResult.Status, true, out ZOperationStatus status)) + if(!Enum.TryParse(operationResult.Status, true, out ZOperationStatus status)) { logger.Error(() => $"Unrecognized operation status: {operationResult.Status}"); break; @@ -338,7 +338,7 @@ private async Task ShieldCoinbaseEmulatedAsync() // get t-addr unspent balance for just the coinbase address (pool wallet) var unspentResult = await daemon.ExecuteCmdSingleAsync(logger, BitcoinCommands.ListUnspent); - if (unspentResult.Error != null) + if(unspentResult.Error != null) { logger.Error(() => $"[{LogCategory}] {BitcoinCommands.ListUnspent} returned error: {unspentResult.Error.Message} code {unspentResult.Error.Code}"); return; @@ -349,7 +349,7 @@ private async Task ShieldCoinbaseEmulatedAsync() .Sum(x => x.Amount); // make sure there's enough balance to shield after reserves - if (balance - TransferFee <= TransferFee) + if(balance - TransferFee <= TransferFee) { logger.Info(() => $"[{LogCategory}] Balance {FormatAmount(balance)} too small for emulated shielding"); return; @@ -378,7 +378,7 @@ private async Task ShieldCoinbaseEmulatedAsync() // send command var sendResult = await daemon.ExecuteCmdSingleAsync(logger, EquihashCommands.ZSendMany, args); - if (sendResult.Error != null) + if(sendResult.Error != null) { logger.Error(() => $"[{LogCategory}] {EquihashCommands.ZSendMany} returned error: {unspentResult.Error.Message} code {unspentResult.Error.Code}"); return; @@ -395,12 +395,12 @@ private async Task ShieldCoinbaseEmulatedAsync() var operationResultResponse = await daemon.ExecuteCmdSingleAsync(logger, EquihashCommands.ZGetOperationResult, new object[] { new object[] { operationId } }); - if (operationResultResponse.Error == null && + if(operationResultResponse.Error == null && operationResultResponse.Response?.Any(x => x.OperationId == operationId) == true) { var operationResult = operationResultResponse.Response.First(x => x.OperationId == operationId); - if (!Enum.TryParse(operationResult.Status, true, out ZOperationStatus status)) + if(!Enum.TryParse(operationResult.Status, true, out ZOperationStatus status)) { logger.Error(() => $"Unrecognized operation status: {operationResult.Status}"); break; diff --git a/src/Miningcore/Blockchain/Equihash/EquihashPool.cs b/src/Miningcore/Blockchain/Equihash/EquihashPool.cs index 5e687e8ee..f1b2ac69e 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashPool.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashPool.cs @@ -70,8 +70,8 @@ public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfi extraConfig = poolConfig.Extra.SafeExtensionDataAs(); - if (poolConfig.Template.As().UsesZCashAddressFormat && - string.IsNullOrEmpty(extraConfig?.ZAddress)) + if(poolConfig.Template.As().UsesZCashAddressFormat && + string.IsNullOrEmpty(extraConfig?.ZAddress)) logger.ThrowLogPoolStartupException($"Pool z-address is not configured"); } @@ -86,7 +86,7 @@ protected override async Task SetupJobManager(CancellationToken ct) await manager.StartAsync(ct); - if (poolConfig.EnableInternalStratum == true) + if(poolConfig.EnableInternalStratum == true) { disposables.Add(manager.Jobs .Select(job => Observable.FromAsync(async () => @@ -96,7 +96,7 @@ protected override async Task SetupJobManager(CancellationToken ct) await OnNewJobAsync(job); } - catch (Exception ex) + catch(Exception ex) { logger.Debug(() => $"{nameof(OnNewJobAsync)}: {ex.Message}"); } @@ -132,7 +132,7 @@ protected async Task OnSubscribeAsync(StratumClient client, Timestamped(); - if (request.Id == null) + if(request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); var requestParams = request.ParamsAs(); @@ -155,7 +155,7 @@ protected async Task OnAuthorizeAsync(StratumClient client, Timestamped(); @@ -174,7 +174,7 @@ protected async Task OnAuthorizeAsync(StratumClient client, Timestamped= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty)) { @@ -222,13 +222,13 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped maxShareAge) + if(requestAge > maxShareAge) { logger.Warn(() => $"[{client.ConnectionId}] Dropping stale share submission request (server overloaded?)"); return; @@ -238,9 +238,9 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped $"[{client.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty, 3)}"); // update pool stats - if (share.IsBlockCandidate) + if(share.IsBlockCandidate) poolStats.LastPoolBlockTime = clock.Now; // update client stats @@ -268,7 +268,7 @@ protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped(); - if (request.Id == null) + if(request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); var requestParams = request.ParamsAs(); var target = requestParams.FirstOrDefault(); - if (!string.IsNullOrEmpty(target)) + if(!string.IsNullOrEmpty(target)) { - if (System.Numerics.BigInteger.TryParse(target, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var targetBig)) + if(System.Numerics.BigInteger.TryParse(target, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var targetBig)) { var newDiff = (double) new BigRational(manager.ChainConfig.Diff1BValue, targetBig); var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port]; - if (newDiff >= poolEndpoint.Difficulty) + if(newDiff >= poolEndpoint.Difficulty) { context.EnqueueNewDifficulty(newDiff); context.ApplyPendingDifficulty(); @@ -373,17 +373,17 @@ protected Task OnNewJobAsync(object jobParams) var tasks = ForEachClient(async client => { - if (!client.IsAlive) + if(!client.IsAlive) return; var context = client.ContextAs(); - if (context.IsSubscribed && context.IsAuthorized) + if(context.IsSubscribed && context.IsAuthorized) { // check alive var lastActivityAgo = clock.Now - context.LastActivity; - if (poolConfig.ClientConnectionTimeout > 0 && + if(poolConfig.ClientConnectionTimeout > 0 && lastActivityAgo.TotalSeconds > poolConfig.ClientConnectionTimeout) { logger.Info(() => $"[{client.ConnectionId}] Booting zombie-worker (idle-timeout exceeded)"); @@ -392,7 +392,7 @@ protected Task OnNewJobAsync(object jobParams) } // varDiff: if the client has a pending difficulty change, apply it now - if (context.ApplyPendingDifficulty()) + if(context.ApplyPendingDifficulty()) await client.NotifyAsync(EquihashStratumMethods.SetTarget, new object[] { EncodeTarget(context.Difficulty) }); // send job @@ -419,7 +419,7 @@ protected override async Task OnVarDiffUpdateAsync(StratumClient client, double context.EnqueueNewDifficulty(newDiff); // apply immediately and notify client - if (context.HasPendingDifficulty) + if(context.HasPendingDifficulty) { context.ApplyPendingDifficulty(); diff --git a/src/Miningcore/Blockchain/Equihash/EquihashUtils.cs b/src/Miningcore/Blockchain/Equihash/EquihashUtils.cs index d44e36f0b..93b0943cf 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashUtils.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashUtils.cs @@ -11,14 +11,14 @@ public static class EquihashUtils public static string EncodeTarget(double difficulty, EquihashCoinTemplate.EquihashNetworkParams chainConfig) { string result; - var diff = BigInteger.ValueOf((long)(difficulty * 255d)); + var diff = BigInteger.ValueOf((long) (difficulty * 255d)); var quotient = chainConfig.Diff1Value.Divide(diff).Multiply(BigInteger.ValueOf(255)); var bytes = quotient.ToByteArray().AsSpan(); Span padded = stackalloc byte[EquihashConstants.TargetPaddingLength]; var padLength = EquihashConstants.TargetPaddingLength - bytes.Length; - if (padLength > 0) + if(padLength > 0) { bytes.CopyTo(padded.Slice(padLength, bytes.Length)); result = padded.ToHexString(0, EquihashConstants.TargetPaddingLength); diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs b/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs index dbf20a688..af24ff363 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs @@ -21,7 +21,7 @@ public EthereumJob(string id, EthereumBlockTemplate blockTemplate, ILogger logge this.logger = logger; var target = blockTemplate.Target; - if (target.StartsWith("0x")) + if(target.StartsWith("0x")) target = target.Substring(2); blockTarget = new uint256(target.HexToReverseByteArray()); @@ -39,7 +39,7 @@ private void RegisterNonce(StratumClient worker, string nonce) { var nonceLower = nonce.ToLower(); - if (!workerNonces.TryGetValue(worker, out var nonces)) + if(!workerNonces.TryGetValue(worker, out var nonces)) { nonces = new HashSet(new[] { nonceLower }); workerNonces[worker] = nonces; @@ -47,7 +47,7 @@ private void RegisterNonce(StratumClient worker, string nonce) else { - if (nonces.Contains(nonceLower)) + if(nonces.Contains(nonceLower)) throw new StratumException(StratumError.MinusOne, "duplicate share"); nonces.Add(nonceLower); @@ -67,14 +67,14 @@ private void RegisterNonce(StratumClient worker, string nonce) var context = worker.ContextAs(); var fullNonceHex = context.ExtraNonce1 + nonce; - if (!ulong.TryParse(fullNonceHex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var fullNonce)) + if(!ulong.TryParse(fullNonceHex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var fullNonce)) throw new StratumException(StratumError.MinusOne, "bad nonce " + fullNonceHex); // get dag for block var dag = await ethash.GetDagAsync(BlockTemplate.Height, logger, ct); // compute - if (!dag.Compute(logger, BlockTemplate.Header.HexToByteArray(), fullNonce, out var mixDigest, out var resultBytes)) + if(!dag.Compute(logger, BlockTemplate.Header.HexToByteArray(), fullNonce, out var mixDigest, out var resultBytes)) throw new StratumException(StratumError.MinusOne, "bad hash"); // test if share meets at least workers current difficulty @@ -86,14 +86,14 @@ private void RegisterNonce(StratumClient worker, string nonce) var ratio = shareDiff / stratumDifficulty; var isBlockCandidate = resultValue <= blockTarget; - if (!isBlockCandidate && ratio < 0.99) + if(!isBlockCandidate && ratio < 0.99) { // check if share matched the previous difficulty from before a vardiff retarget - if (context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue) + if(context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue) { ratio = shareDiff / context.PreviousDifficulty.Value; - if (ratio < 0.99) + if(ratio < 0.99) throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); // use previous difficulty @@ -117,7 +117,7 @@ private void RegisterNonce(StratumClient worker, string nonce) BlockHash = mixDigest.ToHexString(true) }; - if (share.IsBlockCandidate) + if(share.IsBlockCandidate) { fullNonceHex = "0x" + fullNonceHex; var headerHash = BlockTemplate.Header; diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs index 19dc5cc9e..ba769cced 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs @@ -112,7 +112,7 @@ protected bool UpdateJob(EthereumBlockTemplate blockTemplate) try { // may happen if daemon is currently not connected to peers - if (blockTemplate == null || blockTemplate.Header?.Length == 0) + if(blockTemplate == null || blockTemplate.Header?.Length == 0) return false; // logger.Info(() => $"Blocktemplate {blockTemplate.Height}-{blockTemplate.Header}"); @@ -122,7 +122,7 @@ protected bool UpdateJob(EthereumBlockTemplate blockTemplate) job.BlockTemplate.Height < blockTemplate.Height || job.BlockTemplate.Header != blockTemplate.Header; - if (isNew) + if(isNew) { messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); @@ -167,7 +167,7 @@ protected bool UpdateJob(EthereumBlockTemplate blockTemplate) private Task GetBlockTemplateAsync() { - if (isParity) + if(isParity) return GetBlockTemplateParityAsync(); return GetBlockTemplateGethAsync(); @@ -179,13 +179,13 @@ private async Task GetBlockTemplateParityAsync() var response = await daemon.ExecuteCmdAnyAsync(logger, EC.GetWork); - if (response.Error != null) + if(response.Error != null) { logger.Warn(() => $"Error(s) refreshing blocktemplate: {response.Error})"); return null; } - if (response.Response == null) + if(response.Response == null) { logger.Warn(() => $"Error(s) refreshing blocktemplate: {EC.GetWork} returned null response"); return null; @@ -210,9 +210,9 @@ private async Task GetBlockTemplateGethAsync() var results = await daemon.ExecuteBatchAnyAsync(logger, commands); - if (results.Any(x => x.Error != null)) + if(results.Any(x => x.Error != null)) { - logger.Warn(() => $"Error(s) refreshing blocktemplate: {results.First(x=> x.Error != null).Error.Message}"); + logger.Warn(() => $"Error(s) refreshing blocktemplate: {results.First(x => x.Error != null).Error.Message}"); return null; } @@ -221,7 +221,7 @@ private async Task GetBlockTemplateGethAsync() var block = results[1].Response.ToObject(); // append blockheight (parity returns this as 4th element in the getWork response, geth does not) - if (work.Length < 4) + if(work.Length < 4) { var currentHeight = block.Height.Value; work = work.Concat(new[] { (currentHeight + 1).ToStringHexWithPrefix() }).ToArray(); @@ -233,7 +233,7 @@ private async Task GetBlockTemplateGethAsync() private EthereumBlockTemplate AssembleBlockTemplate(string[] work) { - if (work.Length < 4) + if(work.Length < 4) { logger.Error(() => $"Error(s) refreshing blocktemplate: getWork did not return blockheight. Are you really connected to a Parity daemon?"); return null; @@ -261,24 +261,24 @@ private async Task ShowDaemonSyncProgressAsync() var responses = await daemon.ExecuteCmdAllAsync(logger, EC.GetSyncState); var firstValidResponse = responses.FirstOrDefault(x => x.Error == null && x.Response != null)?.Response; - if (firstValidResponse != null) + if(firstValidResponse != null) { // eth_syncing returns false if not synching - if (firstValidResponse is bool) + if(firstValidResponse is bool) return; var syncStates = responses.Where(x => x.Error == null && x.Response != null && firstValidResponse is JObject) .Select(x => ((JObject) x.Response).ToObject()) .ToArray(); - if (syncStates.Any()) + if(syncStates.Any()) { // get peer count var response = await daemon.ExecuteCmdAllAsync(logger, EC.GetPeerCount); var validResponses = response.Where(x => x.Error == null && x.Response != null).ToArray(); var peerCount = validResponses.Any() ? validResponses.Max(x => x.Response.IntegralFromHex()) : 0; - if (syncStates.Any(x => x.WarpChunksAmount != 0)) + if(syncStates.Any(x => x.WarpChunksAmount != 0)) { var warpChunkAmount = syncStates.Min(x => x.WarpChunksAmount); var warpChunkProcessed = syncStates.Max(x => x.WarpChunksProcessed); @@ -287,7 +287,7 @@ private async Task ShowDaemonSyncProgressAsync() logger.Info(() => $"Daemons have downloaded {percent:0.00}% of warp-chunks from {peerCount} peers"); } - else if (syncStates.Any(x => x.HighestBlock != 0)) + else if(syncStates.Any(x => x.HighestBlock != 0)) { var lowestHeight = syncStates.Min(x => x.CurrentBlock); var totalBlocks = syncStates.Max(x => x.HighestBlock); @@ -312,12 +312,12 @@ private async Task UpdateNetworkStatsAsync() var results = await daemon.ExecuteBatchAnyAsync(logger, commands); - if (results.Any(x => x.Error != null)) + if(results.Any(x => x.Error != null)) { var errors = results.Where(x => x.Error != null) .ToArray(); - if (errors.Any()) + if(errors.Any()) logger.Warn(() => $"Error(s) refreshing network stats: {string.Join(", ", errors.Select(y => y.Error.Message))})"); } @@ -344,7 +344,7 @@ private async Task SubmitBlockAsync(Share share, string fullNonceHex, stri mixHash }); - if (response.Error != null || (bool?) response.Response == false) + if(response.Error != null || (bool?) response.Response == false) { var error = response.Error?.Message ?? response?.Response?.ToString(); @@ -361,7 +361,7 @@ private object[] GetJobParamsForStratum(bool isNew) { var job = currentJob; - if (job != null) + if(job != null) { return new object[] { @@ -404,11 +404,11 @@ public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfi base.Configure(poolConfig, clusterConfig); - if (poolConfig.EnableInternalStratum == true) + if(poolConfig.EnableInternalStratum == true) { // ensure dag location is configured - var dagDir = !string.IsNullOrEmpty(extraPoolConfig?.DagDir) ? - Environment.ExpandEnvironmentVariables(extraPoolConfig.DagDir) : + var dagDir = !string.IsNullOrEmpty(extraPoolConfig?.DagDir) ? + Environment.ExpandEnvironmentVariables(extraPoolConfig.DagDir) : Dag.GetDefaultDagDirectory(); // create it if necessary @@ -423,7 +423,7 @@ public bool ValidateAddress(string address) { Contract.Requires(!string.IsNullOrEmpty(address), $"{nameof(address)} must not be empty"); - if (EthereumConstants.ZeroHashPattern.IsMatch(address) || + if(EthereumConstants.ZeroHashPattern.IsMatch(address) || !EthereumConstants.ValidAddressPattern.IsMatch(address)) return false; @@ -452,7 +452,7 @@ public async ValueTask SubmitShareAsync(StratumClient worker, string[] re // stale? lock(jobLock) { - if (!validJobs.TryGetValue(jobId, out job)) + if(!validJobs.TryGetValue(jobId, out job)) throw new StratumException(StratumError.MinusOne, "stale share"); } @@ -466,13 +466,13 @@ public async ValueTask SubmitShareAsync(StratumClient worker, string[] re share.Created = clock.Now; // if block candidate, submit & check if accepted by network - if (share.IsBlockCandidate) + if(share.IsBlockCandidate) { logger.Info(() => $"Submitting block {share.BlockHeight}"); share.IsBlockCandidate = await SubmitBlockAsync(share, fullNonceHex, headerHash, mixHash); - if (share.IsBlockCandidate) + if(share.IsBlockCandidate) { logger.Info(() => $"Daemon accepted block {share.BlockHeight} submitted by {context.Miner}"); } @@ -499,7 +499,7 @@ protected override async Task AreDaemonsHealthyAsync() { var responses = await daemon.ExecuteCmdAllAsync(logger, EC.GetBlockByNumber, new[] { (object) "latest", true }); - if (responses.Where(x => x.Error?.InnerException?.GetType() == typeof(DaemonClientException)) + if(responses.Where(x => x.Error?.InnerException?.GetType() == typeof(DaemonClientException)) .Select(x => (DaemonClientException) x.Error.InnerException) .Any(x => x.Code == HttpStatusCode.Unauthorized)) logger.ThrowLogPoolStartupException($"Daemon reports invalid credentials"); @@ -525,13 +525,13 @@ protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) var isSynched = responses.All(x => x.Error == null && x.Response is bool && (bool) x.Response == false); - if (isSynched) + if(isSynched) { logger.Info(() => $"All daemons synched with blockchain"); break; } - if (!syncPendingNotificationShown) + if(!syncPendingNotificationShown) { logger.Info(() => $"Daemons still syncing with network. Manager will be started once synced"); syncPendingNotificationShown = true; @@ -556,15 +556,15 @@ protected override async Task PostStartInitAsync(CancellationToken ct) var results = await daemon.ExecuteBatchAnyAsync(logger, commands); - if (results.Any(x => x.Error != null)) + if(results.Any(x => x.Error != null)) { - if (results[3].Error != null) + if(results[3].Error != null) isParity = false; var errors = results.Take(3).Where(x => x.Error != null) .ToArray(); - if (errors.Any()) + if(errors.Any()) logger.ThrowLogPoolStartupException($"Init RPC failed: {string.Join(", ", errors.Select(y => y.Error.Message))}"); } @@ -582,7 +582,7 @@ protected override async Task PostStartInitAsync(CancellationToken ct) EthereumUtils.DetectNetworkAndChain(netVersion, parityChain, out networkType, out chainType); - if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) ConfigureRewards(); // update stats @@ -593,14 +593,14 @@ protected override async Task PostStartInitAsync(CancellationToken ct) // Periodically update network stats Observable.Interval(TimeSpan.FromMinutes(10)) - .Select(via => Observable.FromAsync(async ()=> + .Select(via => Observable.FromAsync(async () => { try { await UpdateNetworkStatsAsync(); } - catch (Exception ex) + catch(Exception ex) { logger.Error(ex); } @@ -608,14 +608,14 @@ protected override async Task PostStartInitAsync(CancellationToken ct) .Concat() .Subscribe(); - if (poolConfig.EnableInternalStratum == true) + if(poolConfig.EnableInternalStratum == true) { // make sure we have a current DAG while(true) { var blockTemplate = await GetBlockTemplateAsync(); - if (blockTemplate != null) + if(blockTemplate != null) { logger.Info(() => $"Loading current DAG ..."); @@ -636,7 +636,7 @@ protected override async Task PostStartInitAsync(CancellationToken ct) private void ConfigureRewards() { // Donation to MiningCore development - if (networkType == EthereumNetworkType.Main && + if(networkType == EthereumNetworkType.Main && chainType == ParityChainType.Mainnet && DevDonation.Addresses.TryGetValue(poolConfig.Template.As().Symbol, out var address)) { @@ -654,18 +654,18 @@ private void ConfigureRewards() protected virtual async Task SetupJobUpdatesAsync() { - if (extraPoolConfig?.BtStream == null) + if(extraPoolConfig?.BtStream == null) { var enableStreaming = extraPoolConfig?.EnableDaemonWebsocketStreaming == true; - if (enableStreaming && !poolConfig.Daemons.Any(x => - x.Extra.SafeExtensionDataAs()?.PortWs.HasValue == true)) + if(enableStreaming && !poolConfig.Daemons.Any(x => + x.Extra.SafeExtensionDataAs()?.PortWs.HasValue == true)) { logger.Warn(() => $"'{nameof(EthereumPoolConfigExtra.EnableDaemonWebsocketStreaming).ToLowerCamelCase()}' enabled but not a single daemon found with a configured websocket port ('{nameof(EthereumDaemonEndpointConfigExtra.PortWs).ToLowerCamelCase()}'). Falling back to polling."); enableStreaming = false; } - if (enableStreaming) + if(enableStreaming) { // collect ports var wsDaemons = poolConfig.Daemons @@ -679,10 +679,10 @@ protected virtual async Task SetupJobUpdatesAsync() logger.Info(() => $"Subscribing to WebSocket(s) {string.Join(", ", wsDaemons.Keys.Select(x => $"{(wsDaemons[x].SslWs ? "wss" : "ws")}://{x.Host}:{wsDaemons[x].Value}").Distinct())}"); - if (isParity) + if(isParity) { // stream work updates - var getWorkObs = daemon.WebsocketSubscribe(logger, wsDaemons, EC.ParitySubscribe, new[] { (object)EC.GetWork }) + var getWorkObs = daemon.WebsocketSubscribe(logger, wsDaemons, EC.ParitySubscribe, new[] { (object) EC.GetWork }) .Select(data => { try @@ -691,7 +691,7 @@ protected virtual async Task SetupJobUpdatesAsync() return psp?.Result; } - catch (Exception ex) + catch(Exception ex) { logger.Info(() => $"Error deserializing pending block: {ex.Message}"); } @@ -704,7 +704,7 @@ protected virtual async Task SetupJobUpdatesAsync() .Select(UpdateJob) .Do(isNew => { - if (isNew) + if(isNew) logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected via WebSocket"); }) .Where(isNew => isNew) @@ -717,10 +717,10 @@ protected virtual async Task SetupJobUpdatesAsync() { var wsSubscription = "newHeads"; var isRetry = false; - retry: + retry: // stream work updates - var getWorkObs = daemon.WebsocketSubscribe(logger, wsDaemons, EC.Subscribe, new[] { (object)wsSubscription, new object() }); + var getWorkObs = daemon.WebsocketSubscribe(logger, wsDaemons, EC.Subscribe, new[] { (object) wsSubscription, new object() }); // test subscription var subcriptionResponse = await getWorkObs @@ -728,10 +728,10 @@ protected virtual async Task SetupJobUpdatesAsync() .Select(x => JsonConvert.DeserializeObject>(Encoding.UTF8.GetString(x))) .ToTask(); - if (subcriptionResponse.Error != null) + if(subcriptionResponse.Error != null) { // older versions of geth only support subscriptions to "newBlocks" - if (!isRetry && subcriptionResponse.Error.Code == (int)BitcoinRPCErrorCode.RPC_METHOD_NOT_FOUND) + if(!isRetry && subcriptionResponse.Error.Code == (int) BitcoinRPCErrorCode.RPC_METHOD_NOT_FOUND) { wsSubscription = "newBlocks"; @@ -747,7 +747,7 @@ protected virtual async Task SetupJobUpdatesAsync() .Concat() .Do(isNew => { - if (isNew) + if(isNew) logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected via WebSocket"); }) .Where(isNew => isNew) @@ -766,7 +766,7 @@ protected virtual async Task SetupJobUpdatesAsync() .Concat() .Do(isNew => { - if (isNew) + if(isNew) logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected via RPC-Polling"); }) .Where(isNew => isNew) @@ -786,7 +786,7 @@ protected virtual async Task SetupJobUpdatesAsync() .Select(UpdateJob) .Do(isNew => { - if (isNew) + if(isNew) logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected via BT-Stream"); }) .Where(isNew => isNew) diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs index 7d3da1246..660ba0954 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs @@ -149,7 +149,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); // is it block mined by us? - if (blockInfo.Miner == poolConfig.Address) + if(blockInfo.Miner == poolConfig.Address) { // additional check // NOTE: removal of first character of both sealfields caused by @@ -160,7 +160,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) blockInfo.SealFields[1].Substring(2) == nonce; // mature? - if (match && (latestBlockHeight - block.BlockHeight >= EthereumConstants.MinConfimations)) + if(match && (latestBlockHeight - block.BlockHeight >= EthereumConstants.MinConfimations)) { block.Status = BlockStatus.Confirmed; block.ConfirmationProgress = 1; @@ -168,10 +168,10 @@ public async Task ClassifyBlocksAsync(Block[] blocks) block.Reward = GetBaseBlockReward(chainType, block.BlockHeight); // base reward block.Type = "block"; - if (extraConfig?.KeepUncles == false) + if(extraConfig?.KeepUncles == false) block.Reward += blockInfo.Uncles.Length * (block.Reward / 32); // uncle rewards - if (extraConfig?.KeepTransactionFees == false && blockInfo.Transactions?.Length > 0) + if(extraConfig?.KeepTransactionFees == false && blockInfo.Transactions?.Length > 0) block.Reward += await GetTxRewardAsync(blockInfo); // tx fees logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); @@ -196,7 +196,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) foreach(var blockInfo2 in blockInfo2s) { // don't give up yet, there might be an uncle - if (blockInfo2.Uncles.Length > 0) + if(blockInfo2.Uncles.Length > 0) { // fetch all uncles in a single RPC batch request var uncleBatch = blockInfo2.Uncles.Select((x, index) => new DaemonCmd(EC.GetUncleByBlockNumberAndIndex, @@ -213,10 +213,10 @@ public async Task ClassifyBlocksAsync(Block[] blocks) .Select(x => x.Response.ToObject()) .FirstOrDefault(x => x.Miner == poolConfig.Address); - if (uncle != null) + if(uncle != null) { // mature? - if (latestBlockHeight - uncle.Height.Value >= EthereumConstants.MinConfimations) + if(latestBlockHeight - uncle.Height.Value >= EthereumConstants.MinConfimations) { block.Status = BlockStatus.Confirmed; block.ConfirmationProgress = 1; @@ -237,7 +237,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) } } - if (block.Status == BlockStatus.Pending && block.ConfirmationProgress > 0.75) + if(block.Status == BlockStatus.Pending && block.ConfirmationProgress > 0.75) { // we've lost this one block.Status = BlockStatus.Orphaned; @@ -273,7 +273,7 @@ public async Task PayoutAsync(Balance[] balances) // ensure we have peers var infoResponse = await daemon.ExecuteCmdSingleAsync(logger, EC.GetPeerCount); - if (networkType == EthereumNetworkType.Main && + if(networkType == EthereumNetworkType.Main && (infoResponse.Error != null || string.IsNullOrEmpty(infoResponse.Response) || infoResponse.Response.IntegralFromHex() < EthereumConstants.MinPayoutPeerCount)) { @@ -299,7 +299,7 @@ public async Task PayoutAsync(Balance[] balances) } } - if (txHashes.Any()) + if(txHashes.Any()) NotifyPayoutSuccess(poolConfig.Id, balances, txHashes.ToArray(), null); } @@ -309,7 +309,7 @@ public async Task PayoutAsync(Balance[] balances) { var cacheMisses = blockHeights.Where(x => !blockCache.ContainsKey(x)).ToArray(); - if (cacheMisses.Any()) + if(cacheMisses.Any()) { var blockBatch = cacheMisses.Select(height => new DaemonCmd(EC.GetBlockByNumber, new[] @@ -338,16 +338,16 @@ internal static decimal GetBaseBlockReward(ParityChainType chainType, ulong heig switch(chainType) { case ParityChainType.Mainnet: - if (height >= EthereumConstants.ByzantiumHardForkHeight) + if(height >= EthereumConstants.ByzantiumHardForkHeight) return EthereumConstants.ByzantiumBlockReward; return EthereumConstants.HomesteadBlockReward; case ParityChainType.Classic: - { - var era = Math.Floor(((double) height + 1) / EthereumClassicConstants.BlockPerEra); - return (decimal) Math.Pow((double) EthereumClassicConstants.BasePercent, era) * EthereumClassicConstants.BaseRewardInitial; - } + { + var era = Math.Floor(((double) height + 1) / EthereumClassicConstants.BlockPerEra); + return (decimal) Math.Pow((double) EthereumClassicConstants.BasePercent, era) * EthereumClassicConstants.BaseRewardInitial; + } case ParityChainType.Expanse: return EthereumConstants.ExpanseBlockReward; @@ -375,7 +375,7 @@ private async Task GetTxRewardAsync(DaemonResponses.Block blockInfo) var results = await daemon.ExecuteBatchAnyAsync(logger, batch); - if (results.Any(x => x.Error != null)) + if(results.Any(x => x.Error != null)) throw new Exception($"Error fetching tx receipts: {string.Join(", ", results.Where(x => x.Error != null).Select(y => y.Error.Message))}"); // create lookup table @@ -418,15 +418,15 @@ private async Task DetectChainAsync() var results = await daemon.ExecuteBatchAnyAsync(logger, commands); - if (results.Any(x => x.Error != null)) + if(results.Any(x => x.Error != null)) { - if (results[1].Error != null) + if(results[1].Error != null) isParity = false; var errors = results.Take(1).Where(x => x.Error != null) .ToArray(); - if (errors.Any()) + if(errors.Any()) throw new Exception($"Chain detection failed: {string.Join(", ", errors.Select(y => y.Error.Message))}"); } @@ -442,7 +442,7 @@ private async Task DetectChainAsync() private async Task PayoutAsync(Balance balance) { // unlock account - if (extraConfig.CoinbasePassword != null) + if(extraConfig.CoinbasePassword != null) { var unlockResponse = await daemon.ExecuteCmdSingleAsync(logger, EC.UnlockAccount, new[] { @@ -451,7 +451,7 @@ private async Task PayoutAsync(Balance balance) null }); - if (unlockResponse.Error != null || unlockResponse.Response == null || (bool) unlockResponse.Response == false) + if(unlockResponse.Error != null || unlockResponse.Response == null || (bool) unlockResponse.Response == false) throw new Exception("Unable to unlock coinbase account for sending transaction"); } @@ -467,10 +467,10 @@ private async Task PayoutAsync(Balance balance) var response = await daemon.ExecuteCmdSingleAsync(logger, EC.SendTx, new[] { request }); - if (response.Error != null) + if(response.Error != null) throw new Exception($"{EC.SendTx} returned error: {response.Error.Message} code {response.Error.Code}"); - if (string.IsNullOrEmpty(response.Response) || EthereumConstants.ZeroHashPattern.IsMatch(response.Response)) + if(string.IsNullOrEmpty(response.Response) || EthereumConstants.ZeroHashPattern.IsMatch(response.Response)) throw new Exception($"{EC.SendTx} did not return a valid transaction hash"); var txHash = response.Response; diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs b/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs index 5ef684e1c..707e8eb18 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs @@ -65,12 +65,12 @@ private async Task OnSubscribeAsync(StratumClient client, Timestamped(); - if (request.Id == null) + if(request.Id == null) throw new StratumException(StratumError.Other, "missing request id"); var requestParams = request.ParamsAs(); - if (requestParams == null || requestParams.Length < 2 || requestParams.Any(string.IsNullOrEmpty)) + if(requestParams == null || requestParams.Length < 2 || requestParams.Any(string.IsNullOrEmpty)) throw new StratumException(StratumError.MinusOne, "invalid request"); manager.PrepareWorker(client); @@ -99,7 +99,7 @@ private async Task OnAuthorizeAsync(StratumClient client, Timestamped(); - if (request.Id == null) + if(request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); var requestParams = request.ParamsAs(); @@ -122,7 +122,7 @@ private async Task OnAuthorizeAsync(StratumClient client, Timestamped= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty)) { @@ -145,28 +145,28 @@ private async Task OnSubmitAsync(StratumClient client, Timestamped maxShareAge) + if(requestAge > maxShareAge) { logger.Warn(() => $"[{client.ConnectionId}] Dropping stale share submission request (server overloaded?)"); return; } // validate worker - if (!context.IsAuthorized) + if(!context.IsAuthorized) throw new StratumException(StratumError.UnauthorizedWorker, "unauthorized worker"); - else if (!context.IsSubscribed) + else if(!context.IsSubscribed) throw new StratumException(StratumError.NotSubscribed, "not subscribed"); // check request var submitRequest = request.ParamsAs(); - if (submitRequest.Length != 3 || + if(submitRequest.Length != 3 || submitRequest.Any(string.IsNullOrEmpty)) throw new StratumException(StratumError.MinusOne, "malformed PoW result"); @@ -189,7 +189,7 @@ private async Task OnSubmitAsync(StratumClient client, Timestamped(); var sendInitialWork = false; - lock (context) + lock(context) { - if (context.IsSubscribed && context.IsAuthorized && !context.IsInitialWorkSent) + if(context.IsSubscribed && context.IsAuthorized && !context.IsInitialWorkSent) { context.IsInitialWorkSent = true; sendInitialWork = true; } } - if (sendInitialWork) + if(sendInitialWork) { // send intial update await client.NotifyAsync(EthereumStratumMethods.SetDifficulty, new object[] { context.Difficulty }); @@ -243,17 +243,17 @@ protected virtual Task OnNewJobAsync(object jobParams) var tasks = ForEachClient(async client => { - if (!client.IsAlive) + if(!client.IsAlive) return; var context = client.ContextAs(); - if (context.IsSubscribed && context.IsAuthorized && context.IsInitialWorkSent) + if(context.IsSubscribed && context.IsAuthorized && context.IsInitialWorkSent) { // check alive var lastActivityAgo = clock.Now - context.LastActivity; - if (poolConfig.ClientConnectionTimeout > 0 && + if(poolConfig.ClientConnectionTimeout > 0 && lastActivityAgo.TotalSeconds > poolConfig.ClientConnectionTimeout) { logger.Info(() => $"[{client.ConnectionId}] Booting zombie-worker (idle-timeout exceeded)"); @@ -262,7 +262,7 @@ protected virtual Task OnNewJobAsync(object jobParams) } // varDiff: if the client has a pending difficulty change, apply it now - if (context.ApplyPendingDifficulty()) + if(context.ApplyPendingDifficulty()) await client.NotifyAsync(EthereumStratumMethods.SetDifficulty, new object[] { context.Difficulty }); // send job @@ -282,7 +282,7 @@ protected override async Task SetupJobManager(CancellationToken ct) await manager.StartAsync(ct); - if (poolConfig.EnableInternalStratum == true) + if(poolConfig.EnableInternalStratum == true) { disposables.Add(manager.Jobs .Select(job => Observable.FromAsync(async () => @@ -292,7 +292,7 @@ protected override async Task SetupJobManager(CancellationToken ct) await OnNewJobAsync(job); } - catch (Exception ex) + catch(Exception ex) { logger.Debug(() => $"{nameof(OnNewJobAsync)}: {ex.Message}"); } @@ -378,7 +378,7 @@ protected override async Task OnVarDiffUpdateAsync(StratumClient client, double // apply immediately and notify client var context = client.ContextAs(); - if (context.HasPendingDifficulty) + if(context.HasPendingDifficulty) { context.ApplyPendingDifficulty(); @@ -394,7 +394,7 @@ public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfi // validate mandatory extra config var extraConfig = poolConfig.PaymentProcessing?.Extra?.SafeExtensionDataAs(); - if (clusterConfig.PaymentProcessing?.Enabled == true && extraConfig?.CoinbasePassword == null) + if(clusterConfig.PaymentProcessing?.Enabled == true && extraConfig?.CoinbasePassword == null) logger.ThrowLogPoolStartupException("\"paymentProcessing.coinbasePassword\" pool-configuration property missing or empty (required for unlocking wallet during payment processing)"); } diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumUtils.cs b/src/Miningcore/Blockchain/Ethereum/EthereumUtils.cs index c06ca00ee..b97af4bc7 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumUtils.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumUtils.cs @@ -8,11 +8,11 @@ public static void DetectNetworkAndChain(string netVersionResponse, string parit out EthereumNetworkType networkType, out ParityChainType chainType) { // convert network - if (int.TryParse(netVersionResponse, out var netWorkTypeInt)) + if(int.TryParse(netVersionResponse, out var netWorkTypeInt)) { networkType = (EthereumNetworkType) netWorkTypeInt; - if (!Enum.IsDefined(typeof(EthereumNetworkType), networkType)) + if(!Enum.IsDefined(typeof(EthereumNetworkType), networkType)) networkType = EthereumNetworkType.Unknown; } @@ -20,15 +20,15 @@ public static void DetectNetworkAndChain(string netVersionResponse, string parit networkType = EthereumNetworkType.Unknown; // convert chain - if (!Enum.TryParse(parityChainResponse, true, out chainType)) + if(!Enum.TryParse(parityChainResponse, true, out chainType)) { - if (parityChainResponse.ToLower() == "ethereum classic") + if(parityChainResponse.ToLower() == "ethereum classic") chainType = ParityChainType.Classic; else chainType = ParityChainType.Unknown; } - if (chainType == ParityChainType.Foundation) + if(chainType == ParityChainType.Foundation) chainType = ParityChainType.Mainnet; } } diff --git a/src/Miningcore/Blockchain/ExtraNonceProviderBase.cs b/src/Miningcore/Blockchain/ExtraNonceProviderBase.cs index 9cfcc36bf..44694686b 100644 --- a/src/Miningcore/Blockchain/ExtraNonceProviderBase.cs +++ b/src/Miningcore/Blockchain/ExtraNonceProviderBase.cs @@ -57,7 +57,7 @@ public string Next() lock(counterLock) { counter++; - if (counter > nonceMax) + if(counter > nonceMax) counter = 0; // encode to hex diff --git a/src/Miningcore/Blockchain/JobManagerBase.cs b/src/Miningcore/Blockchain/JobManagerBase.cs index 3a93a52af..fa3ce2885 100644 --- a/src/Miningcore/Blockchain/JobManagerBase.cs +++ b/src/Miningcore/Blockchain/JobManagerBase.cs @@ -89,7 +89,7 @@ protected string NextJobId(string format = null) Interlocked.Increment(ref jobId); var value = Interlocked.CompareExchange(ref jobId, 0, Int32.MinValue); - if (format != null) + if(format != null) return value.ToString(format); return value.ToStringHex8(); diff --git a/src/Miningcore/Configuration/ClusterConfigExtensions.cs b/src/Miningcore/Configuration/ClusterConfigExtensions.cs index 9f7e3bd7d..d1f419d39 100644 --- a/src/Miningcore/Configuration/ClusterConfigExtensions.cs +++ b/src/Miningcore/Configuration/ClusterConfigExtensions.cs @@ -32,7 +32,7 @@ public BitcoinTemplate() { coinbaseHasherValue = new Lazy(() => { - if (CoinbaseHasher == null) + if(CoinbaseHasher == null) return null; return HashAlgorithmFactory.GetHash(ComponentContext, CoinbaseHasher); @@ -40,7 +40,7 @@ public BitcoinTemplate() headerHasherValue = new Lazy(() => { - if (HeaderHasher == null) + if(HeaderHasher == null) return null; return HashAlgorithmFactory.GetHash(ComponentContext, HeaderHasher); @@ -48,7 +48,7 @@ public BitcoinTemplate() blockHasherValue = new Lazy(() => { - if (BlockHasher == null) + if(BlockHasher == null) return null; return HashAlgorithmFactory.GetHash(ComponentContext, BlockHasher); @@ -56,7 +56,7 @@ public BitcoinTemplate() posBlockHasherValue = new Lazy(() => { - if (PoSBlockHasher == null) + if(PoSBlockHasher == null) return null; return HashAlgorithmFactory.GetHash(ComponentContext, PoSBlockHasher); @@ -81,8 +81,8 @@ public override string GetAlgorithmName() { var hash = HeaderHasherValue; - if (hash.GetType() == typeof(DigestReverser)) - return ((DigestReverser)hash).Upstream.GetType().Name; + if(hash.GetType() == typeof(DigestReverser)) + return ((DigestReverser) hash).Upstream.GetType().Name; return hash.GetType().Name; } @@ -106,7 +106,7 @@ public EquihashNetworkParams() diff1BValue = new Lazy(() => { - if (string.IsNullOrEmpty(Diff1)) + if(string.IsNullOrEmpty(Diff1)) throw new InvalidOperationException("Diff1 has not yet been initialized"); return BigInteger.Parse(Diff1, NumberStyles.HexNumber); @@ -161,7 +161,7 @@ public partial class CryptonoteCoinTemplate public override string GetAlgorithmName() { - switch (Hash) + switch(Hash) { case CryptonightHashType.Normal: return "Cryptonight"; diff --git a/src/Miningcore/Configuration/ClusterConfigValidation.cs b/src/Miningcore/Configuration/ClusterConfigValidation.cs index dce479979..df22d1548 100644 --- a/src/Miningcore/Configuration/ClusterConfigValidation.cs +++ b/src/Miningcore/Configuration/ClusterConfigValidation.cs @@ -183,7 +183,7 @@ public PoolConfigValidator() RuleFor(j => j.Ports) .Must((pc, ports, ctx) => { - if (ports?.Keys.Any(port => port < 0) == true) + if(ports?.Keys.Any(port => port < 0) == true) { ctx.MessageFormatter.AppendArgument("port", ports.Keys.First(port => port < 0)); return false; @@ -234,7 +234,7 @@ public ClusterConfigValidator() .GroupBy(x => x.Id) .ToArray(); - if (ids.Any(id => id.Count() > 1)) + if(ids.Any(id => id.Count() > 1)) { ctx.MessageFormatter.AppendArgument("poolId", ids.First(id => id.Count() > 1).Key); return false; @@ -254,7 +254,7 @@ public ClusterConfigValidator() foreach(var port in ports) { - if (port.Count() > 1) + if(port.Count() > 1) { ctx.MessageFormatter.AppendArgument("port", port.Key); return false; @@ -340,7 +340,7 @@ public void Validate() var validator = new ClusterConfigValidator(); var result = validator.Validate(this); - if (!result.IsValid) + if(!result.IsValid) throw new ValidationException(result.Errors); } } diff --git a/src/Miningcore/Configuration/CoinTemplateLoader.cs b/src/Miningcore/Configuration/CoinTemplateLoader.cs index 277849c1c..4d8a9a62e 100644 --- a/src/Miningcore/Configuration/CoinTemplateLoader.cs +++ b/src/Miningcore/Configuration/CoinTemplateLoader.cs @@ -16,26 +16,26 @@ public static class CoinTemplateLoader private static IEnumerable> LoadTemplates(string filename, JsonSerializer serializer, IComponentContext ctx) { - using (var jreader = new JsonTextReader(File.OpenText(filename))) + using(var jreader = new JsonTextReader(File.OpenText(filename))) { var jo = serializer.Deserialize(jreader); - foreach (var o in jo) + foreach(var o in jo) { - if (o.Value.Type != JTokenType.Object) + if(o.Value.Type != JTokenType.Object) logger.ThrowLogPoolStartupException("Invalid coin-template file: dictionary of coin-templates expected"); var value = o.Value[nameof(CoinTemplate.Family).ToLower()]; - if (value == null) + if(value == null) logger.ThrowLogPoolStartupException("Invalid coin-template: missing 'family' property"); var family = value.ToObject(); - var result = (CoinTemplate)o.Value.ToObject(CoinTemplate.Families[family]); + var result = (CoinTemplate) o.Value.ToObject(CoinTemplate.Families[family]); ctx.InjectProperties(result); // Patch explorer links - if ((result.ExplorerBlockLinks == null || result.ExplorerBlockLinks.Count == 0) && + if((result.ExplorerBlockLinks == null || result.ExplorerBlockLinks.Count == 0) && !string.IsNullOrEmpty(result.ExplorerBlockLink)) { result.ExplorerBlockLinks = new Dictionary @@ -63,16 +63,16 @@ public static Dictionary Load(IComponentContext ctx, strin var result = new Dictionary(); - foreach (var filename in coinDefs) + foreach(var filename in coinDefs) { var definitions = LoadTemplates(filename, serializer, ctx).ToArray(); - foreach (var definition in definitions) + foreach(var definition in definitions) { var coinId = definition.Key; // log redefinitions - if (result.ContainsKey(coinId)) + if(result.ContainsKey(coinId)) logger.Warn($"Redefinition of coin '{coinId}' in file {filename}. First seen in {result[coinId].Source}"); result[coinId] = definition.Value; diff --git a/src/Miningcore/Contracts/Contract.cs b/src/Miningcore/Contracts/Contract.cs index 4de061f49..e2797c73e 100644 --- a/src/Miningcore/Contracts/Contract.cs +++ b/src/Miningcore/Contracts/Contract.cs @@ -33,7 +33,7 @@ public class Contract public static void Requires(bool predicate, string message = null) where TException : Exception, new() { - if (!predicate) + if(!predicate) { var constructor = constructors.GetOrAdd(typeof(TException), CreateConstructor); throw constructor(new object[] { message }); @@ -43,7 +43,7 @@ public static void Requires(bool predicate, string message = null) [ContractAnnotation("parameter:null => halt")] public static void RequiresNonNull(object parameter, string paramName) { - if (parameter == null) + if(parameter == null) throw new ArgumentNullException(paramName); } @@ -64,7 +64,7 @@ private static ConstructorDelegate CreateConstructor(Type type) // To feed the constructor with the right parameters, we need to generate an array // of parameters that will be read from the initialize object array argument. var constructorParameters = parameters.Select((paramType, index) => - // convert the object[index] to the right constructor parameter type. + // convert the object[index] to the right constructor parameter type. Expression.Convert( // read a value from the object[index] Expression.ArrayAccess( diff --git a/src/Miningcore/Crypto/HashAlgorithmFactory.cs b/src/Miningcore/Crypto/HashAlgorithmFactory.cs index b9c6d6cf9..bf7354ced 100644 --- a/src/Miningcore/Crypto/HashAlgorithmFactory.cs +++ b/src/Miningcore/Crypto/HashAlgorithmFactory.cs @@ -20,7 +20,7 @@ public static IHashAlgorithm GetHash(IComponentContext ctx, JObject definition) throw new NotSupportedException("$Invalid or empty hash value {hash}"); var args = definition["args"]? - .Select(token => token.Type == JTokenType.Object ? GetHash(ctx, (JObject)token) : token.Value()) + .Select(token => token.Type == JTokenType.Object ? GetHash(ctx, (JObject) token) : token.Value()) .ToArray(); return InstantiateHash(ctx, hash, args); @@ -29,19 +29,19 @@ public static IHashAlgorithm GetHash(IComponentContext ctx, JObject definition) private static IHashAlgorithm InstantiateHash(IComponentContext ctx, string name, object[] args) { // special handling for DigestReverser - if (name == "reverse") + if(name == "reverse") name = nameof(DigestReverser); // check cache if possible var hasArgs = args != null && args.Length > 0; - if (!hasArgs && cache.TryGetValue(name, out var result)) + if(!hasArgs && cache.TryGetValue(name, out var result)) return result; var hashClass = (typeof(Sha256D).Namespace + "." + name).ToLower(); var hashType = typeof(Sha256D).Assembly.GetType(hashClass, true, true); // create it (we'll let Autofac do the heavy lifting) - if (hasArgs) + if(hasArgs) result = (IHashAlgorithm) ctx.Resolve(hashType, args.Select((x, i) => new PositionalParameter(i, x))); else { diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Kezzak.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Kezzak.cs index d5d3bbae9..91be8c5d6 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Kezzak.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Kezzak.cs @@ -41,13 +41,13 @@ public void Digest(ReadOnlySpan data, Span result, params object[] e Span dataEx = stackalloc byte[data.Length + nTimeHex.Length]; data.CopyTo(dataEx); - if (nTimeHex.Length > 0) + if(nTimeHex.Length > 0) { var dest = dataEx.Slice(data.Length); nTimeHex.CopyTo(dest); } - fixed(byte* input = dataEx) + fixed (byte* input = dataEx) { fixed (byte* output = result) { diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/ScryptN.cs b/src/Miningcore/Crypto/Hashing/Algorithms/ScryptN.cs index 4e74c7383..c60f82a21 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/ScryptN.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/ScryptN.cs @@ -55,11 +55,11 @@ public void Digest(ReadOnlySpan data, Span result, params object[] e Contract.Requires(result.Length >= 32, $"{nameof(result)} must be greater or equal 32 bytes"); // get nFactor - var ts = ((DateTimeOffset)Clock.Now).ToUnixTimeSeconds(); + var ts = ((DateTimeOffset) Clock.Now).ToUnixTimeSeconds(); var n = timetable.First(x => ts >= x.Item2).Item1; var nFactor = Math.Log(n) / Math.Log(2); - fixed(byte* input = data) + fixed (byte* input = data) { fixed (byte* output = result) { diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Sha256D.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Sha256D.cs index 5323b09a9..fd6a90412 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Sha256D.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Sha256D.cs @@ -33,7 +33,7 @@ public void Digest(ReadOnlySpan data, Span result, params object[] e { Contract.Requires(result.Length >= 32, $"{nameof(result)} must be greater or equal 32 bytes"); - using (var hasher = SHA256.Create()) + using(var hasher = SHA256.Create()) { hasher.TryComputeHash(data, result, out var cb); hasher.TryComputeHash(result, result, out cb); diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Sha256S.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Sha256S.cs index d8ed61dc9..4295b59c1 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Sha256S.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Sha256S.cs @@ -33,7 +33,7 @@ public void Digest(ReadOnlySpan data, Span result, params object[] e { Contract.Requires(result.Length >= 32, $"{nameof(result)} must be greater or equal 32 bytes"); - using (var hasher = SHA256.Create()) + using(var hasher = SHA256.Create()) { hasher.TryComputeHash(data, result, out var cb); } diff --git a/src/Miningcore/Crypto/Hashing/Equihash/EquihashSolver.cs b/src/Miningcore/Crypto/Hashing/Equihash/EquihashSolver.cs index e3ad03299..16b7ea1bf 100644 --- a/src/Miningcore/Crypto/Hashing/Equihash/EquihashSolver.cs +++ b/src/Miningcore/Crypto/Hashing/Equihash/EquihashSolver.cs @@ -35,7 +35,7 @@ public static int MaxThreads get => maxThreads; set { - if (sem.IsValueCreated) + if(sem.IsValueCreated) throw new InvalidOperationException("Too late: semaphore already created"); maxThreads = value; diff --git a/src/Miningcore/Crypto/Hashing/Equihash/EquihashSolverFactory.cs b/src/Miningcore/Crypto/Hashing/Equihash/EquihashSolverFactory.cs index 124a14cb6..4b75ba32d 100644 --- a/src/Miningcore/Crypto/Hashing/Equihash/EquihashSolverFactory.cs +++ b/src/Miningcore/Crypto/Hashing/Equihash/EquihashSolverFactory.cs @@ -32,7 +32,7 @@ public static EquihashSolver GetSolver(IComponentContext ctx, JObject definition private static EquihashSolver InstantiateSolver(IComponentContext ctx, object[] args) { var key = string.Join("-", args); - if (cache.TryGetValue(key, out var result)) + if(cache.TryGetValue(key, out var result)) return result; var n = (int) Convert.ChangeType(args[0], typeof(int)); @@ -49,7 +49,7 @@ private static EquihashSolver InstantiateSolver(IComponentContext ctx, object[] result = (EquihashSolver) ctx.Resolve(hashType, new PositionalParameter(0, personalization)); } - catch (ComponentNotRegisteredException) + catch(ComponentNotRegisteredException) { throw new NotSupportedException($"Equihash variant {n}_{k} is currently not implemented"); } diff --git a/src/Miningcore/Crypto/Hashing/Ethash/Cache.cs b/src/Miningcore/Crypto/Hashing/Ethash/Cache.cs index 4b48f94e7..7d31c6bd7 100644 --- a/src/Miningcore/Crypto/Hashing/Ethash/Cache.cs +++ b/src/Miningcore/Crypto/Hashing/Ethash/Cache.cs @@ -25,7 +25,7 @@ public Cache(ulong epoch) public void Dispose() { - if (handle != IntPtr.Zero) + if(handle != IntPtr.Zero) { LibMultihash.ethash_light_delete(handle); handle = IntPtr.Zero; @@ -38,7 +38,7 @@ await Task.Run(() => { lock(genLock) { - if (!isGenerated) + if(!isGenerated) { var started = DateTime.Now; logger.Debug(() => $"Generating cache for epoch {Epoch}"); @@ -64,12 +64,12 @@ public unsafe bool Compute(ILogger logger, byte[] hash, ulong nonce, out byte[] var value = new LibMultihash.ethash_return_value(); - fixed(byte* input = hash) + fixed (byte* input = hash) { LibMultihash.ethash_light_compute(handle, input, nonce, ref value); } - if (value.success) + if(value.success) { mixDigest = value.mix_hash.value; result = value.result.value; diff --git a/src/Miningcore/Crypto/Hashing/Ethash/Dag.cs b/src/Miningcore/Crypto/Hashing/Ethash/Dag.cs index 24551f7ab..a51952482 100644 --- a/src/Miningcore/Crypto/Hashing/Ethash/Dag.cs +++ b/src/Miningcore/Crypto/Hashing/Ethash/Dag.cs @@ -29,14 +29,14 @@ public static unsafe string GetDefaultDagDirectory() { var chars = new byte[512]; - fixed(byte* data = chars) + fixed (byte* data = chars) { - if (LibMultihash.ethash_get_default_dirname(data, chars.Length)) + if(LibMultihash.ethash_get_default_dirname(data, chars.Length)) { int length; for(length = 0; length < chars.Length; length++) { - if (data[length] == 0) + if(data[length] == 0) break; } @@ -49,7 +49,7 @@ public static unsafe string GetDefaultDagDirectory() public void Dispose() { - if (handle != IntPtr.Zero) + if(handle != IntPtr.Zero) { LibMultihash.ethash_full_delete(handle); handle = IntPtr.Zero; @@ -60,7 +60,7 @@ public async ValueTask GenerateAsync(string dagDir, ILogger logger, Cancellation { Contract.Requires(!string.IsNullOrEmpty(dagDir), $"{nameof(dagDir)} must not be empty"); - if (handle == IntPtr.Zero) + if(handle == IntPtr.Zero) { await Task.Run(() => { @@ -69,7 +69,7 @@ await Task.Run(() => sem.WaitOne(); // re-check after obtaining lock - if (handle != IntPtr.Zero) + if(handle != IntPtr.Zero) return; logger.Info(() => $"Generating DAG for epoch {Epoch}"); @@ -90,7 +90,7 @@ await Task.Run(() => return !ct.IsCancellationRequested ? 0 : 1; }); - if (handle == IntPtr.Zero) + if(handle == IntPtr.Zero) throw new OutOfMemoryException("ethash_full_new IO or memory error"); logger.Info(() => $"Done generating DAG for epoch {Epoch} after {DateTime.Now - started}"); @@ -98,7 +98,7 @@ await Task.Run(() => finally { - if (light != IntPtr.Zero) + if(light != IntPtr.Zero) LibMultihash.ethash_light_delete(light); } } @@ -122,12 +122,12 @@ public unsafe bool Compute(ILogger logger, byte[] hash, ulong nonce, out byte[] var value = new LibMultihash.ethash_return_value(); - fixed(byte* input = hash) + fixed (byte* input = hash) { LibMultihash.ethash_full_compute(handle, input, nonce, ref value); } - if (value.success) + if(value.success) { mixDigest = value.mix_hash.value; result = value.result.value; diff --git a/src/Miningcore/Crypto/Hashing/Ethash/EthashFull.cs b/src/Miningcore/Crypto/Hashing/Ethash/EthashFull.cs index ee6b6f6c5..4310c9b8e 100644 --- a/src/Miningcore/Crypto/Hashing/Ethash/EthashFull.cs +++ b/src/Miningcore/Crypto/Hashing/Ethash/EthashFull.cs @@ -38,10 +38,10 @@ public async Task GetDagAsync(ulong block, ILogger logger, CancellationToke lock(cacheLock) { - if (numCaches == 0) + if(numCaches == 0) numCaches = 3; - if (!caches.TryGetValue(epoch, out result)) + if(!caches.TryGetValue(epoch, out result)) { // No cached DAG, evict the oldest if the cache limit was reached while(caches.Count >= numCaches) @@ -56,7 +56,7 @@ public async Task GetDagAsync(ulong block, ILogger logger, CancellationToke } // If we have the new DAG pre-generated, use that, otherwise create a new one - if (future != null && future.Epoch == epoch) + if(future != null && future.Epoch == epoch) { logger.Debug(() => $"Using pre-generated DAG for epoch {epoch}"); @@ -74,7 +74,7 @@ public async Task GetDagAsync(ulong block, ILogger logger, CancellationToke } // If we used up the future cache, or need a refresh, regenerate - else if (future == null || future.Epoch <= epoch) + else if(future == null || future.Epoch <= epoch) { logger.Info(() => $"Pre-generating DAG for epoch {epoch + 1}"); future = new Dag(epoch + 1); diff --git a/src/Miningcore/Crypto/MerkleTree.cs b/src/Miningcore/Crypto/MerkleTree.cs index fe8af89a4..3527baf56 100644 --- a/src/Miningcore/Crypto/MerkleTree.cs +++ b/src/Miningcore/Crypto/MerkleTree.cs @@ -87,15 +87,15 @@ private IList CalculateSteps(IEnumerable hashList) var startL = 2; var Ll = L.Count; - if (Ll > 1) + if(Ll > 1) while(true) { - if (Ll == 1) + if(Ll == 1) break; steps.Add(L[1]); - if (Ll % 2 == 1) + if(Ll % 2 == 1) L.Add(L[L.Count - 1]); var Ld = new List(); diff --git a/src/Miningcore/DaemonInterface/DaemonClient.cs b/src/Miningcore/DaemonInterface/DaemonClient.cs index f086a005a..3655e0446 100644 --- a/src/Miningcore/DaemonInterface/DaemonClient.cs +++ b/src/Miningcore/DaemonInterface/DaemonClient.cs @@ -109,7 +109,7 @@ public void Configure(DaemonEndpointConfig[] endPoints, string digestAuthRealm = // create one HttpClient instance per endpoint that carries the associated credentials httpClients = endPoints.ToDictionary(endpoint => endpoint, endpoint => { - if (string.IsNullOrEmpty(endpoint.User) || !endpoint.DigestAuth) + if(string.IsNullOrEmpty(endpoint.User) || !endpoint.DigestAuth) return defaultHttpClient; return new HttpClient(new SocketsHttpHandler @@ -331,15 +331,15 @@ private async Task BuildRequestTask(ILogger logger, DaemonEndpo // build request url var protocol = (endPoint.Ssl || endPoint.Http2) ? "https" : "http"; var requestUrl = $"{protocol}://{endPoint.Host}:{endPoint.Port}"; - if (!string.IsNullOrEmpty(endPoint.HttpPath)) + if(!string.IsNullOrEmpty(endPoint.HttpPath)) requestUrl += $"{(endPoint.HttpPath.StartsWith("/") ? string.Empty : "/")}{endPoint.HttpPath}"; // build http request - using (var request = new HttpRequestMessage(HttpMethod.Post, requestUrl)) + using(var request = new HttpRequestMessage(HttpMethod.Post, requestUrl)) { request.Headers.ConnectionClose = false; // enable keep-alive - if (endPoint.Http2) + if(endPoint.Http2) request.Version = new Version(2, 0); // build request content @@ -347,7 +347,7 @@ private async Task BuildRequestTask(ILogger logger, DaemonEndpo request.Content = new StringContent(json, Encoding.UTF8, "application/json"); // build auth header - if (!string.IsNullOrEmpty(endPoint.User) && !endPoint.DigestAuth) + if(!string.IsNullOrEmpty(endPoint.User) && !endPoint.DigestAuth) { var auth = $"{endPoint.User}:{endPoint.Password}"; var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(auth)); @@ -357,13 +357,13 @@ private async Task BuildRequestTask(ILogger logger, DaemonEndpo logger.Trace(() => $"Sending RPC request to {requestUrl}: {json}"); // send request - using (var response = await httpClients[endPoint].SendAsync(request, ct)) + using(var response = await httpClients[endPoint].SendAsync(request, ct)) { // read response var responseContent = await response.Content.ReadAsStringAsync(); // deserialize response - using (var jreader = new JsonTextReader(new StringReader(responseContent))) + using(var jreader = new JsonTextReader(new StringReader(responseContent))) { var result = serializer.Deserialize(jreader); @@ -389,7 +389,7 @@ private async Task[]> BuildBatchRequestTask(ILogger logg // build request url var protocol = (endPoint.Ssl || endPoint.Http2) ? "https" : "http"; var requestUrl = $"{protocol}://{endPoint.Host}:{endPoint.Port}"; - if (!string.IsNullOrEmpty(endPoint.HttpPath)) + if(!string.IsNullOrEmpty(endPoint.HttpPath)) requestUrl += $"{(endPoint.HttpPath.StartsWith("/") ? string.Empty : "/")}{endPoint.HttpPath}"; // build http request @@ -397,7 +397,7 @@ private async Task[]> BuildBatchRequestTask(ILogger logg { request.Headers.ConnectionClose = false; // enable keep-alive - if (endPoint.Http2) + if(endPoint.Http2) request.Version = new Version(2, 0); // build request content @@ -405,7 +405,7 @@ private async Task[]> BuildBatchRequestTask(ILogger logg request.Content = new StringContent(json, Encoding.UTF8, "application/json"); // build auth header - if (!string.IsNullOrEmpty(endPoint.User) && !endPoint.DigestAuth) + if(!string.IsNullOrEmpty(endPoint.User) && !endPoint.DigestAuth) { var auth = $"{endPoint.User}:{endPoint.Password}"; var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(auth)); @@ -420,7 +420,7 @@ private async Task[]> BuildBatchRequestTask(ILogger logg // deserialize response var jsonResponse = await response.Content.ReadAsStringAsync(); - using (var jreader = new JsonTextReader(new StringReader(jsonResponse))) + using(var jreader = new JsonTextReader(new StringReader(jsonResponse))) { var result = serializer.Deserialize[]>(jreader); @@ -448,22 +448,22 @@ private DaemonResponse MapDaemonResponse(int i, Task MapDaemonResponse(int i, Task(serializer); else resp.Response = (TResponse) x.Result?.Result; @@ -485,7 +485,7 @@ private DaemonResponse MapDaemonResponse(int i, Task[] MapDaemonBatchResponse(int i, Task[]> x) { - if (x.IsFaulted) + if(x.IsFaulted) return x.Result?.Select(y => new DaemonResponse { Instance = endPoints[i], @@ -516,7 +516,7 @@ private IObservable WebsocketSubscribeEndpoint(ILogger logger, DaemonEnd { var buf = new byte[0x10000]; - while (!cts.IsCancellationRequested) + while(!cts.IsCancellationRequested) { try { @@ -541,7 +541,7 @@ private IObservable WebsocketSubscribeEndpoint(ILogger logger, DaemonEnd // stream response var stream = new MemoryStream(); - while (!cts.IsCancellationRequested && client.State == WebSocketState.Open) + while(!cts.IsCancellationRequested && client.State == WebSocketState.Open) { stream.SetLength(0); var complete = false; @@ -557,7 +557,7 @@ private IObservable WebsocketSubscribeEndpoint(ILogger logger, DaemonEnd var response = await client.ReceiveAsync(buf, ctsComposite.Token); - if (response.MessageType == WebSocketMessageType.Binary) + if(response.MessageType == WebSocketMessageType.Binary) throw new InvalidDataException("expected text, received binary data"); stream.Write(buf, 0, response.Count); @@ -567,7 +567,7 @@ private IObservable WebsocketSubscribeEndpoint(ILogger logger, DaemonEnd } } while(!complete && !cts.IsCancellationRequested && client.State == WebSocketState.Open); - logger.Debug(()=> $"Received WebSocket message with length {stream.Length}"); + logger.Debug(() => $"Received WebSocket message with length {stream.Length}"); // publish obs.OnNext(stream.ToArray()); diff --git a/src/Miningcore/Extensions/ArrayExtensions.cs b/src/Miningcore/Extensions/ArrayExtensions.cs index 83923446a..28fdab436 100644 --- a/src/Miningcore/Extensions/ArrayExtensions.cs +++ b/src/Miningcore/Extensions/ArrayExtensions.cs @@ -71,20 +71,20 @@ public static string ToHexString(this Span value, bool withPrefix = false) public static string ToHexString(this Span value, int? off, int? len, bool withPrefix = false) { - if (value == null || value.Length == 0) + if(value == null || value.Length == 0) return string.Empty; var length = len ?? value.Length; var bufferSize = length * 2; - if (withPrefix) + if(withPrefix) bufferSize += 2; Span buffer = stackalloc char[bufferSize]; var offset = 0; - if (withPrefix) + if(withPrefix) { buffer[offset++] = '0'; buffer[offset++] = 'x'; diff --git a/src/Miningcore/Extensions/ConnectionFactoryExtensions.cs b/src/Miningcore/Extensions/ConnectionFactoryExtensions.cs index c5348e8db..6155e0ea4 100644 --- a/src/Miningcore/Extensions/ConnectionFactoryExtensions.cs +++ b/src/Miningcore/Extensions/ConnectionFactoryExtensions.cs @@ -34,7 +34,7 @@ public static class ConnectionFactoryExtensions public static async Task Run(this IConnectionFactory factory, Func action) { - using (var con = await factory.OpenConnectionAsync()) + using(var con = await factory.OpenConnectionAsync()) { await action(con); } @@ -69,7 +69,7 @@ public static async Task RunTx(this IConnectionFactory factory, { await action(con, tx); - if (autoCommit) + if(autoCommit) tx.Commit(); } @@ -99,7 +99,7 @@ public static async Task RunTx(this IConnectionFactory factory, { var result = await func(con, tx); - if (autoCommit) + if(autoCommit) tx.Commit(); return result; diff --git a/src/Miningcore/Extensions/DictionaryExtensions.cs b/src/Miningcore/Extensions/DictionaryExtensions.cs index 1fe0a60a7..99d4040cf 100644 --- a/src/Miningcore/Extensions/DictionaryExtensions.cs +++ b/src/Miningcore/Extensions/DictionaryExtensions.cs @@ -35,7 +35,7 @@ public static void StripValue(this IDictionary dict, string key) var keyActual = dict.Keys.FirstOrDefault(x => x.ToLower(CultureInfo.InvariantCulture) == key); - if (keyActual != null) + if(keyActual != null) { var result = dict.Remove(keyActual); Debug.Assert(result); diff --git a/src/Miningcore/Extensions/HttpContextExtensions.cs b/src/Miningcore/Extensions/HttpContextExtensions.cs index 8ebaeeea9..2e6feb893 100644 --- a/src/Miningcore/Extensions/HttpContextExtensions.cs +++ b/src/Miningcore/Extensions/HttpContextExtensions.cs @@ -9,7 +9,7 @@ public static class HttpContextExtensions public static T GetQueryParameter(this HttpContext ctx, string name, T defaultValue) { var stringVal = ctx.Request.Query[name].FirstOrDefault(); - if (string.IsNullOrEmpty(stringVal)) + if(string.IsNullOrEmpty(stringVal)) return defaultValue; return (T) Convert.ChangeType(stringVal, typeof(T)); diff --git a/src/Miningcore/Extensions/LoggingExtensions.cs b/src/Miningcore/Extensions/LoggingExtensions.cs index 0523adef3..0460a8509 100644 --- a/src/Miningcore/Extensions/LoggingExtensions.cs +++ b/src/Miningcore/Extensions/LoggingExtensions.cs @@ -11,7 +11,7 @@ public static class LoggingExtensions { public static void LogInvoke(this ILogger logger, object[] args = null, [CallerMemberName] string caller = null) { - if (args == null) + if(args == null) logger.Debug(() => $"{caller}()"); else logger.Debug(() => $"{caller}({string.Join(", ", args.Select(x => x?.ToString()))})"); @@ -19,7 +19,7 @@ public static void LogInvoke(this ILogger logger, object[] args = null, [CallerM public static void LogInvoke(this ILogger logger, string logCat, object[] args = null, [CallerMemberName] string caller = null) { - if (args == null) + if(args == null) logger.Debug(() => $"[{logCat}] {caller}()"); else logger.Debug(() => $"[{logCat}] {caller}({string.Join(", ", args.Select(x => x?.ToString()))})"); diff --git a/src/Miningcore/Extensions/MessageBusExtensions.cs b/src/Miningcore/Extensions/MessageBusExtensions.cs index 04d340eaa..322486dd5 100644 --- a/src/Miningcore/Extensions/MessageBusExtensions.cs +++ b/src/Miningcore/Extensions/MessageBusExtensions.cs @@ -14,7 +14,7 @@ public static void NotifyBlockFound(this IMessageBus messageBus, string poolId, // miner account explorer link string minerExplorerLink = null; - if (!string.IsNullOrEmpty(coin.ExplorerAccountLink)) + if(!string.IsNullOrEmpty(coin.ExplorerAccountLink)) minerExplorerLink = string.Format(coin.ExplorerAccountLink, block.Miner); messageBus.SendMessage(new BlockFoundNotification @@ -46,19 +46,19 @@ public static void NotifyBlockUnlocked(this IMessageBus messageBus, string poolI string blockExplorerLink = null; string minerExplorerLink = null; - if (block.Status != BlockStatus.Orphaned) + if(block.Status != BlockStatus.Orphaned) { // block explorer link - if (coin.ExplorerBlockLinks.TryGetValue(!string.IsNullOrEmpty(block.Type) ? block.Type : "block", out var blockInfobaseUrl)) + if(coin.ExplorerBlockLinks.TryGetValue(!string.IsNullOrEmpty(block.Type) ? block.Type : "block", out var blockInfobaseUrl)) { - if (blockInfobaseUrl.Contains(CoinMetaData.BlockHeightPH)) + if(blockInfobaseUrl.Contains(CoinMetaData.BlockHeightPH)) blockExplorerLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHeightPH, block.BlockHeight.ToString(CultureInfo.InvariantCulture)); - else if (blockInfobaseUrl.Contains(CoinMetaData.BlockHashPH) && !string.IsNullOrEmpty(block.Hash)) + else if(blockInfobaseUrl.Contains(CoinMetaData.BlockHashPH) && !string.IsNullOrEmpty(block.Hash)) blockExplorerLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHashPH, block.Hash); } // miner account explorer link - if (!string.IsNullOrEmpty(coin.ExplorerAccountLink)) + if(!string.IsNullOrEmpty(coin.ExplorerAccountLink)) minerExplorerLink = string.Format(coin.ExplorerAccountLink, block.Miner); } diff --git a/src/Miningcore/Extensions/NumberExtensions.cs b/src/Miningcore/Extensions/NumberExtensions.cs index 3fd37bd4f..ae8fb13ab 100644 --- a/src/Miningcore/Extensions/NumberExtensions.cs +++ b/src/Miningcore/Extensions/NumberExtensions.cs @@ -27,7 +27,7 @@ public static class NumberExtensions { public static uint ToBigEndian(this uint value) { - if (BitConverter.IsLittleEndian) + if(BitConverter.IsLittleEndian) return (uint) IPAddress.NetworkToHostOrder((int) value); return value; @@ -35,7 +35,7 @@ public static uint ToBigEndian(this uint value) public static uint ToLittleEndian(this uint value) { - if (!BitConverter.IsLittleEndian) + if(!BitConverter.IsLittleEndian) return (uint) IPAddress.HostToNetworkOrder((int) value); return value; diff --git a/src/Miningcore/Extensions/PipelineExtensions.cs b/src/Miningcore/Extensions/PipelineExtensions.cs index 70d809513..822bdeeca 100644 --- a/src/Miningcore/Extensions/PipelineExtensions.cs +++ b/src/Miningcore/Extensions/PipelineExtensions.cs @@ -7,7 +7,7 @@ public static class PipelineExtensions { public static ReadOnlySpan ToSpan(this ReadOnlySequence buffer) { - if (buffer.IsSingleSegment) + if(buffer.IsSingleSegment) return buffer.First.Span; return buffer.ToArray(); diff --git a/src/Miningcore/Extensions/SerializationExtensions.cs b/src/Miningcore/Extensions/SerializationExtensions.cs index 5c9e3c579..de1ead5fd 100644 --- a/src/Miningcore/Extensions/SerializationExtensions.cs +++ b/src/Miningcore/Extensions/SerializationExtensions.cs @@ -28,7 +28,7 @@ public static class SerializationExtensions { public static T SafeExtensionDataAs(this IDictionary extra) { - if (extra != null) + if(extra != null) { try { diff --git a/src/Miningcore/Extensions/StringExtensions.cs b/src/Miningcore/Extensions/StringExtensions.cs index 19b2bfca0..ab13b17f8 100644 --- a/src/Miningcore/Extensions/StringExtensions.cs +++ b/src/Miningcore/Extensions/StringExtensions.cs @@ -36,13 +36,13 @@ public static class StringExtensions /// public static byte[] HexToByteArray(this string str) { - if (str.StartsWith("0x")) + if(str.StartsWith("0x")) str = str.Substring(2); var arr = new byte[str.Length >> 1]; var count = str.Length >> 1; - for (var i = 0; i < count; ++i) + for(var i = 0; i < count; ++i) arr[i] = (byte) ((GetHexVal(str[i << 1]) << 4) + GetHexVal(str[(i << 1) + 1])); return arr; @@ -55,14 +55,14 @@ public static byte[] HexToByteArray(this string str) /// public static byte[] HexToReverseByteArray(this string str) { - if (str.StartsWith("0x")) + if(str.StartsWith("0x")) str = str.Substring(2); var arr = new byte[str.Length >> 1]; var count = str.Length >> 1; - for (var i = 0; i < count; ++i) - arr[count - 1 - i] = (byte)((GetHexVal(str[i << 1]) << 4) + GetHexVal(str[(i << 1) + 1])); + for(var i = 0; i < count; ++i) + arr[count - 1 - i] = (byte) ((GetHexVal(str[i << 1]) << 4) + GetHexVal(str[(i << 1) + 1])); return arr; } @@ -85,7 +85,7 @@ public static string ToStringHex8(this int value) public static string ToStringHexWithPrefix(this ulong value) { - if (value == 0) + if(value == 0) return "0x0"; return "0x" + value.ToString("x", CultureInfo.InvariantCulture); @@ -93,7 +93,7 @@ public static string ToStringHexWithPrefix(this ulong value) public static string ToStringHexWithPrefix(this long value) { - if (value == 0) + if(value == 0) return "0x0"; return "0x" + value.ToString("x", CultureInfo.InvariantCulture); @@ -101,7 +101,7 @@ public static string ToStringHexWithPrefix(this long value) public static string ToStringHexWithPrefix(this uint value) { - if (value == 0) + if(value == 0) return "0x0"; return "0x" + value.ToString("x", CultureInfo.InvariantCulture); @@ -109,7 +109,7 @@ public static string ToStringHexWithPrefix(this uint value) public static string ToStringHexWithPrefix(this int value) { - if (value == 0) + if(value == 0) return "0x0"; return "0x" + value.ToString("x", CultureInfo.InvariantCulture); @@ -117,7 +117,7 @@ public static string ToStringHexWithPrefix(this int value) public static string StripHexPrefix(this string value) { - if (value?.ToLower().StartsWith("0x") == true) + if(value?.ToLower().StartsWith("0x") == true) return value.Substring(2); return value; @@ -127,10 +127,10 @@ public static T IntegralFromHex(this string value) { var underlyingType = Nullable.GetUnderlyingType(typeof(T)); - if (value.StartsWith("0x")) + if(value.StartsWith("0x")) value = value.Substring(2); - if (!ulong.TryParse(value, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out var val)) + if(!ulong.TryParse(value, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out var val)) throw new FormatException(); return (T) Convert.ChangeType(val, underlyingType ?? typeof(T)); @@ -138,7 +138,7 @@ public static T IntegralFromHex(this string value) public static string ToLowerCamelCase(this string str) { - if (string.IsNullOrEmpty(str)) + if(string.IsNullOrEmpty(str)) return str; return char.ToLowerInvariant(str[0]) + str.Substring(1); @@ -151,7 +151,7 @@ public static string AsString(this ReadOnlySequence line, Encoding encodin public static string Capitalize(this string str) { - if (string.IsNullOrEmpty(str)) + if(string.IsNullOrEmpty(str)) return str; return str.Substring(0, 1).ToUpper() + str.Substring(1); diff --git a/src/Miningcore/Extensions/ZmqExtensions.cs b/src/Miningcore/Extensions/ZmqExtensions.cs index ef85260de..4fb2e5e27 100644 --- a/src/Miningcore/Extensions/ZmqExtensions.cs +++ b/src/Miningcore/Extensions/ZmqExtensions.cs @@ -20,7 +20,7 @@ public static class ZmqExtensions private static readonly Lazy<(byte[] PubKey, byte[] SecretKey)> ownKey = new Lazy<(byte[] PubKey, byte[] SecretKey)>(() => { - if (!ZContext.Has("curve")) + if(!ZContext.Has("curve")) throw new NotSupportedException("ZMQ library does not support curve"); Z85.CurveKeypair(out var pubKey, out var secretKey); @@ -32,7 +32,7 @@ public static class ZmqExtensions private static byte[] DeriveKey(string password, int length = 32) { - using (var kbd = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(password), NoSalt, PasswordIterations)) + using(var kbd = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(password), NoSalt, PasswordIterations)) { var block = kbd.GetBytes(length); return block; @@ -43,7 +43,7 @@ private static byte[] DeriveKey(string password, int length = 32) public static IObservable MonitorAsObservable(this ZSocket socket) { - return Observable.Defer(() => Observable.Create(obs=> + return Observable.Defer(() => Observable.Create(obs => { var url = $"inproc://monitor{Interlocked.Increment(ref monitorSocketIndex)}"; var monitor = ZMonitor.Create(socket.Context, url); @@ -72,7 +72,7 @@ void OnEvent(object sender, ZMonitorEventArgs e) public static void LogMonitorEvent(ILogger logger, ZMonitorEventArgs e) { - logger.Info(()=> $"[ZMQ] [{e.Event.Address}] {Enum.GetName(typeof(ZMonitorEvents), e.Event.Event)} [{e.Event.EventValue}]"); + logger.Info(() => $"[ZMQ] [{e.Event.Address}] {Enum.GetName(typeof(ZMonitorEvents), e.Event.Event)} [{e.Event.EventValue}]"); } /// @@ -82,17 +82,17 @@ public static void SetupCurveTlsServer(this ZSocket socket, string keyPlain, ILo { keyPlain = keyPlain?.Trim(); - if (string.IsNullOrEmpty(keyPlain)) + if(string.IsNullOrEmpty(keyPlain)) return; - if (!ZContext.Has("curve")) + if(!ZContext.Has("curve")) logger.ThrowLogPoolStartupException("Unable to initialize ZMQ Curve Transport-Layer-Security. Your ZMQ library was compiled without Curve support!"); // Get server's public key byte[] keyBytes = null; byte[] serverPubKey = null; - if (!knownKeys.TryGetValue(keyPlain, out var serverKeys)) + if(!knownKeys.TryGetValue(keyPlain, out var serverKeys)) { keyBytes = DeriveKey(keyPlain, 32); @@ -120,16 +120,16 @@ public static void SetupCurveTlsClient(this ZSocket socket, string keyPlain, ILo { keyPlain = keyPlain?.Trim(); - if (string.IsNullOrEmpty(keyPlain)) + if(string.IsNullOrEmpty(keyPlain)) return; - if (!ZContext.Has("curve")) + if(!ZContext.Has("curve")) logger.ThrowLogPoolStartupException("Unable to initialize ZMQ Curve Transport-Layer-Security. Your ZMQ library was compiled without Curve support!"); // Get server's public key byte[] serverPubKey = null; - if (!knownKeys.TryGetValue(keyPlain, out var serverKeys)) + if(!knownKeys.TryGetValue(keyPlain, out var serverKeys)) { var keyBytes = DeriveKey(keyPlain, 32); diff --git a/src/Miningcore/JsonRpc/JsonRpcRequest.cs b/src/Miningcore/JsonRpc/JsonRpcRequest.cs index a8639012d..6925f9a1c 100644 --- a/src/Miningcore/JsonRpc/JsonRpcRequest.cs +++ b/src/Miningcore/JsonRpc/JsonRpcRequest.cs @@ -63,7 +63,7 @@ public JsonRpcRequest(string method, T parameters, object id) public TParam ParamsAs() where TParam : class { - if (Params is JToken) + if(Params is JToken) return ((JToken) Params)?.ToObject(); return (TParam) Params; diff --git a/src/Miningcore/JsonRpc/JsonRpcResponse.cs b/src/Miningcore/JsonRpc/JsonRpcResponse.cs index b88cd070f..dc73352b1 100644 --- a/src/Miningcore/JsonRpc/JsonRpcResponse.cs +++ b/src/Miningcore/JsonRpc/JsonRpcResponse.cs @@ -60,7 +60,7 @@ public JsonRpcResponse(JsonRpcException ex, object id, object result) Error = ex; Id = id; - if (result != null) + if(result != null) Result = JToken.FromObject(result); } @@ -78,7 +78,7 @@ public JsonRpcResponse(JsonRpcException ex, object id, object result) public TParam ResultAs() where TParam : class { - if (Result is JToken) + if(Result is JToken) return ((JToken) Result)?.ToObject(); return (TParam) Result; diff --git a/src/Miningcore/Messaging/MessageBus.cs b/src/Miningcore/Messaging/MessageBus.cs index f15b45736..f7d01bc1d 100644 --- a/src/Miningcore/Messaging/MessageBus.cs +++ b/src/Miningcore/Messaging/MessageBus.cs @@ -164,7 +164,7 @@ private ISubject setupSubjectIfNecessary(string contract) withMessageBus(typeof(T), contract, (mb, tuple) => { - if (mb.TryGetValue(tuple, out var subjRef) && subjRef.IsAlive) + if(mb.TryGetValue(tuple, out var subjRef) && subjRef.IsAlive) { ret = (ISubject) subjRef.Target; return; @@ -186,7 +186,7 @@ private void withMessageBus( { var tuple = new Tuple(type, contract); block(messageBus, tuple); - if (messageBus.ContainsKey(tuple) && !messageBus[tuple].IsAlive) + if(messageBus.ContainsKey(tuple) && !messageBus[tuple].IsAlive) messageBus.Remove(tuple); } } diff --git a/src/Miningcore/Mining/BtStreamReceiver.cs b/src/Miningcore/Mining/BtStreamReceiver.cs index 9d5da27bc..233acee75 100644 --- a/src/Miningcore/Mining/BtStreamReceiver.cs +++ b/src/Miningcore/Mining/BtStreamReceiver.cs @@ -56,7 +56,7 @@ private void StartMessageReceiver(ZmqPubSubEndpointConfig[] endpoints) .DistinctBy(x => $"{x.Url}:{x.SharedEncryptionKey}") .ToArray(); - while (!cts.IsCancellationRequested) + while(!cts.IsCancellationRequested) { // track last message received per endpoint var lastMessageReceived = relays.Select(_ => clock.Now).ToArray(); @@ -66,29 +66,29 @@ private void StartMessageReceiver(ZmqPubSubEndpointConfig[] endpoints) // setup sockets var sockets = relays.Select(SetupSubSocket).ToArray(); - using (new CompositeDisposable(sockets)) + using(new CompositeDisposable(sockets)) { var pollItems = sockets.Select(_ => ZPollItem.CreateReceiver()).ToArray(); - while (!cts.IsCancellationRequested) + while(!cts.IsCancellationRequested) { - if (sockets.PollIn(pollItems, out var messages, out var error, timeout)) + if(sockets.PollIn(pollItems, out var messages, out var error, timeout)) { - for (var i = 0; i < messages.Length; i++) + for(var i = 0; i < messages.Length; i++) { var msg = messages[i]; - if (msg != null) + if(msg != null) { lastMessageReceived[i] = clock.Now; - using (msg) + using(msg) { ProcessMessage(msg); } } - else if (clock.Now - lastMessageReceived[i] > reconnectTimeout) + else if(clock.Now - lastMessageReceived[i] > reconnectTimeout) { // re-create socket sockets[i].Dispose(); @@ -101,18 +101,18 @@ private void StartMessageReceiver(ZmqPubSubEndpointConfig[] endpoints) } } - if (error != null) + if(error != null) logger.Error(() => $"{nameof(ShareReceiver)}: {error.Name} [{error.Name}] during receive"); } } } } - catch (Exception ex) + catch(Exception ex) { logger.Error(() => $"{nameof(ShareReceiver)}: {ex}"); - if (!cts.IsCancellationRequested) + if(!cts.IsCancellationRequested) Thread.Sleep(1000); } } @@ -126,7 +126,7 @@ private static ZSocket SetupSubSocket(ZmqPubSubEndpointConfig relay) subSocket.Connect(relay.Url); subSocket.SubscribeAll(); - if (subSocket.CurveServerKey != null) + if(subSocket.CurveServerKey != null) logger.Info($"Monitoring Bt-Stream source {relay.Url} using Curve public-key {subSocket.CurveServerKey.ToHexString()}"); else logger.Info($"Monitoring Bt-Stream source {relay.Url}"); @@ -143,17 +143,17 @@ private void ProcessMessage(ZMessage msg) var sent = DateTimeOffset.FromUnixTimeMilliseconds(msg[3].ReadInt64()).DateTime; // TMP FIX - if (flags != 0 && ((flags & 1) == 0)) + if(flags != 0 && ((flags & 1) == 0)) flags = BitConverter.ToUInt32(BitConverter.GetBytes(flags).ToNewReverseArray()); // compressed - if ((flags & 1) == 1) + if((flags & 1) == 1) { - using (var stm = new MemoryStream(data)) + using(var stm = new MemoryStream(data)) { - using (var stmOut = new MemoryStream()) + using(var stmOut = new MemoryStream()) { - using (var ds = new DeflateStream(stm, CompressionMode.Decompress)) + using(var ds = new DeflateStream(stm, CompressionMode.Decompress)) { ds.CopyTo(stmOut); } @@ -177,14 +177,14 @@ public void Start(ClusterConfig clusterConfig) this.clusterConfig = clusterConfig; var endpoints = clusterConfig.Pools.Select(x => - x.Extra.SafeExtensionDataAs()?.BtStream ?? + x.Extra.SafeExtensionDataAs()?.BtStream ?? x.Extra.SafeExtensionDataAs()?.BtStream ?? x.Extra.SafeExtensionDataAs()?.BtStream) .Where(x => x != null) - .DistinctBy(x=> $"{x.Url}:{x.SharedEncryptionKey}") + .DistinctBy(x => $"{x.Url}:{x.SharedEncryptionKey}") .ToArray(); - if (endpoints.Any()) + if(endpoints.Any()) StartMessageReceiver(endpoints); } diff --git a/src/Miningcore/Mining/PoolBase.cs b/src/Miningcore/Mining/PoolBase.cs index b98f69045..ada725565 100644 --- a/src/Miningcore/Mining/PoolBase.cs +++ b/src/Miningcore/Mining/PoolBase.cs @@ -96,17 +96,17 @@ protected PoolBase(IComponentContext ctx, protected double? GetStaticDiffFromPassparts(string[] parts) { - if (parts == null || parts.Length == 0) + if(parts == null || parts.Length == 0) return null; foreach(var part in parts) { var m = regexStaticDiff.Match(part); - if (m.Success) + if(m.Success) { var str = m.Groups[1].Value.Trim(); - if (double.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out var diff) && + if(double.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out var diff) && !double.IsNaN(diff) && !double.IsInfinity(diff)) return diff; } @@ -125,7 +125,7 @@ protected override void OnConnect(StratumClient client, IPEndPoint ipEndPoint) client.SetContext(context); // varDiff setup - if (context.VarDiff != null) + if(context.VarDiff != null) { lock(context.VarDiff) { @@ -141,12 +141,12 @@ private void EnsureNoZombieClient(StratumClient client) { Observable.Timer(clock.Now.AddSeconds(10)) .TakeUntil(client.Terminated) - .Where(_=> client.IsAlive) + .Where(_ => client.IsAlive) .Subscribe(_ => { try { - if (client.LastReceive == null) + if(client.LastReceive == null) { logger.Info(() => $"[{client.ConnectionId}] Booting zombie-worker (post-connect silence)"); @@ -154,7 +154,7 @@ private void EnsureNoZombieClient(StratumClient client) } } - catch (Exception ex) + catch(Exception ex) { logger.Error(ex); } @@ -175,7 +175,7 @@ protected async Task UpdateVarDiffAsync(StratumClient client, bool isIdleUpdate { var context = client.ContextAs(); - if (context.VarDiff != null) + if(context.VarDiff != null) { logger.Debug(() => $"[{client.ConnectionId}] Updating VarDiff" + (isIdleUpdate ? " [idle]" : string.Empty)); @@ -185,7 +185,7 @@ protected async Task UpdateVarDiffAsync(StratumClient client, bool isIdleUpdate lock(varDiffManagers) { - if (!varDiffManagers.TryGetValue(poolEndpoint, out varDiffManager)) + if(!varDiffManagers.TryGetValue(poolEndpoint, out varDiffManager)) { varDiffManager = new VarDiffManager(poolEndpoint.VarDiff, clock); varDiffManagers[poolEndpoint] = varDiffManager; @@ -202,7 +202,7 @@ protected async Task UpdateVarDiffAsync(StratumClient client, bool isIdleUpdate newDiff = varDiffManager.Update(context.VarDiff, context.Difficulty, isIdleUpdate); } - if (newDiff != null) + if(newDiff != null) { logger.Info(() => $"[{client.ConnectionId}] VarDiff update to {Math.Round(newDiff.Value, 2)}"); @@ -223,7 +223,7 @@ private void StartVarDiffIdleUpdate(StratumClient client, PoolEndpoint poolEndpo var shareReceived = messageBus.Listen() .Where(x => x.Share.PoolId == poolConfig.Id && x.Client == client) - .Select(_=> Unit.Default) + .Select(_ => Unit.Default) .Take(1); var timeout = poolEndpoint.VarDiff.TargetTime; @@ -251,7 +251,7 @@ protected virtual Task OnVarDiffUpdateAsync(StratumClient client, double newDiff protected void SetupBanning(ClusterConfig clusterConfig) { - if (poolConfig.Banning?.Enabled == true) + if(poolConfig.Banning?.Enabled == true) { var managerType = clusterConfig.Banning?.Manager ?? BanManagerKind.Integrated; banManager = ctx.ResolveKeyed(managerType); @@ -260,7 +260,7 @@ protected void SetupBanning(ClusterConfig clusterConfig) protected virtual async Task InitStatsAsync() { - if (clusterConfig.ShareRelay == null) + if(clusterConfig.ShareRelay == null) await LoadStatsAsync(); } @@ -272,7 +272,7 @@ private async Task LoadStatsAsync() var stats = await cf.Run(con => statsRepo.GetLastPoolStatsAsync(con, poolConfig.Id)); - if (stats != null) + if(stats != null) { poolStats = mapper.Map(stats); blockchainStats = mapper.Map(stats); @@ -289,11 +289,11 @@ protected void ConsiderBan(StratumClient client, WorkerContextBase context, Pool { var totalShares = context.Stats.ValidShares + context.Stats.InvalidShares; - if (totalShares > config.CheckThreshold) + if(totalShares > config.CheckThreshold) { var ratioBad = (double) context.Stats.InvalidShares / totalShares; - if (ratioBad < config.InvalidPercent / 100.0) + if(ratioBad < config.InvalidPercent / 100.0) { // reset stats context.Stats.ValidShares = 0; @@ -302,7 +302,7 @@ protected void ConsiderBan(StratumClient client, WorkerContextBase context, Pool else { - if (poolConfig.Banning?.Enabled == true && + if(poolConfig.Banning?.Enabled == true && (clusterConfig.Banning?.BanOnInvalidShares.HasValue == false || clusterConfig.Banning?.BanOnInvalidShares == true)) { @@ -319,7 +319,7 @@ protected void ConsiderBan(StratumClient client, WorkerContextBase context, Pool private (IPEndPoint IPEndPoint, PoolEndpoint PoolEndpoint) PoolEndpoint2IPEndpoint(int port, PoolEndpoint pep) { var listenAddress = IPAddress.Parse("127.0.0.1"); - if (!string.IsNullOrEmpty(pep.ListenAddress)) + if(!string.IsNullOrEmpty(pep.ListenAddress)) listenAddress = pep.ListenAddress != "*" ? IPAddress.Parse(pep.ListenAddress) : IPAddress.Any; return (new IPEndPoint(listenAddress, port), pep); @@ -338,7 +338,7 @@ private void OutputPoolInfo() Network Difficulty: {blockchainStats.NetworkDifficulty} Network Hash Rate: {FormatUtil.FormatHashrate(blockchainStats.NetworkHashrate)} Stratum Port(s): {(poolConfig.Ports?.Any() == true ? string.Join(", ", poolConfig.Ports.Keys) : string.Empty)} -Pool Fee: {(poolConfig.RewardRecipients?.Any() == true ? poolConfig.RewardRecipients.Where(x=> x.Type != "dev").Sum(x => x.Percentage) : 0)}% +Pool Fee: {(poolConfig.RewardRecipients?.Any() == true ? poolConfig.RewardRecipients.Where(x => x.Type != "dev").Sum(x => x.Percentage) : 0)}% "; logger.Info(() => msg); @@ -374,7 +374,7 @@ public virtual async Task StartAsync(CancellationToken ct) await SetupJobManager(ct); await InitStatsAsync(); - if (poolConfig.EnableInternalStratum == true) + if(poolConfig.EnableInternalStratum == true) { var ipEndpoints = poolConfig.Ports.Keys .Select(port => PoolEndpoint2IPEndpoint(port, poolConfig.Ports[port])) diff --git a/src/Miningcore/Mining/ShareReceiver.cs b/src/Miningcore/Mining/ShareReceiver.cs index 6fc4daf65..94966f7c7 100644 --- a/src/Miningcore/Mining/ShareReceiver.cs +++ b/src/Miningcore/Mining/ShareReceiver.cs @@ -78,7 +78,7 @@ private void StartMessageReceiver() .DistinctBy(x => $"{x.Url}:{x.SharedEncryptionKey}") .ToArray(); - while (!cts.IsCancellationRequested) + while(!cts.IsCancellationRequested) { // track last message received per endpoint var lastMessageReceived = relays.Select(_ => clock.Now).ToArray(); @@ -88,26 +88,26 @@ private void StartMessageReceiver() // setup sockets var sockets = relays.Select(SetupSubSocket).ToArray(); - using (new CompositeDisposable(sockets)) + using(new CompositeDisposable(sockets)) { var pollItems = sockets.Select(_ => ZPollItem.CreateReceiver()).ToArray(); - while (!cts.IsCancellationRequested) + while(!cts.IsCancellationRequested) { - if (sockets.PollIn(pollItems, out var messages, out var error, timeout)) + if(sockets.PollIn(pollItems, out var messages, out var error, timeout)) { - for (var i = 0; i < messages.Length; i++) + for(var i = 0; i < messages.Length; i++) { var msg = messages[i]; - if (msg != null) + if(msg != null) { lastMessageReceived[i] = clock.Now; queue.Post((relays[i].Url, msg)); } - else if (clock.Now - lastMessageReceived[i] > reconnectTimeout) + else if(clock.Now - lastMessageReceived[i] > reconnectTimeout) { // re-create socket sockets[i].Dispose(); @@ -120,18 +120,18 @@ private void StartMessageReceiver() } } - if (error != null) + if(error != null) logger.Error(() => $"{nameof(ShareReceiver)}: {error.Name} [{error.Name}] during receive"); } } } } - catch (Exception ex) + catch(Exception ex) { logger.Error(() => $"{nameof(ShareReceiver)}: {ex}"); - if (!cts.IsCancellationRequested) + if(!cts.IsCancellationRequested) Thread.Sleep(5000); } } @@ -145,7 +145,7 @@ private static ZSocket SetupSubSocket(ShareRelayEndpointConfig relay) subSocket.Connect(relay.Url); subSocket.SubscribeAll(); - if (subSocket.CurveServerKey != null) + if(subSocket.CurveServerKey != null) logger.Info($"Monitoring external stratum {relay.Url} using Curve public-key {subSocket.CurveServerKey.ToHexString()}"); else logger.Info($"Monitoring external stratum {relay.Url}"); @@ -155,7 +155,7 @@ private static ZSocket SetupSubSocket(ShareRelayEndpointConfig relay) private void StartMessageProcessors() { - for (var i = 0; i < Environment.ProcessorCount; i++) + for(var i = 0; i < Environment.ProcessorCount; i++) ProcessMessages(); } @@ -163,19 +163,19 @@ private void ProcessMessages() { Task.Run(async () => { - while (!cts.IsCancellationRequested) + while(!cts.IsCancellationRequested) { try { var (url, msg) = await queue.ReceiveAsync(cts.Token); - using (msg) + using(msg) { ProcessMessage(url, msg); } } - catch (Exception ex) + catch(Exception ex) { logger.Error(ex); } @@ -191,35 +191,35 @@ private void ProcessMessage(string url, ZMessage msg) var data = msg[2].Read(); // validate - if (string.IsNullOrEmpty(topic) || !pools.ContainsKey(topic)) + if(string.IsNullOrEmpty(topic) || !pools.ContainsKey(topic)) { logger.Warn(() => $"Received share for pool '{topic}' which is not known locally. Ignoring ..."); return; } - if (data?.Length == 0) + if(data?.Length == 0) { logger.Warn(() => $"Received empty data from {url}/{topic}. Ignoring ..."); return; } // TMP FIX - if ((flags & ShareRelay.WireFormatMask) == 0) + if((flags & ShareRelay.WireFormatMask) == 0) flags = BitConverter.ToUInt32(BitConverter.GetBytes(flags).ToNewReverseArray()); // deserialize - var wireFormat = (ShareRelay.WireFormat)(flags & ShareRelay.WireFormatMask); + var wireFormat = (ShareRelay.WireFormat) (flags & ShareRelay.WireFormatMask); Share share = null; - switch (wireFormat) + switch(wireFormat) { case ShareRelay.WireFormat.Json: - using (var stream = new MemoryStream(data)) + using(var stream = new MemoryStream(data)) { - using (var reader = new StreamReader(stream, Encoding.UTF8)) + using(var reader = new StreamReader(stream, Encoding.UTF8)) { - using (var jreader = new JsonTextReader(reader)) + using(var jreader = new JsonTextReader(reader)) { share = serializer.Deserialize(jreader); } @@ -229,10 +229,10 @@ private void ProcessMessage(string url, ZMessage msg) break; case ShareRelay.WireFormat.ProtocolBuffers: - using (var stream = new MemoryStream(data)) + using(var stream = new MemoryStream(data)) { share = Serializer.Deserialize(stream); - share.BlockReward = (decimal)share.BlockRewardDouble; + share.BlockReward = (decimal) share.BlockRewardDouble; } break; @@ -242,7 +242,7 @@ private void ProcessMessage(string url, ZMessage msg) break; } - if (share == null) + if(share == null) { logger.Error(() => $"Unable to deserialize share received from {url}/{topic}"); return; @@ -254,7 +254,7 @@ private void ProcessMessage(string url, ZMessage msg) messageBus.SendMessage(new ClientShare(null, share)); // update poolstats from shares - if (pools.TryGetValue(topic, out var poolContext)) + if(pools.TryGetValue(topic, out var poolContext)) { var pool = poolContext.Pool; @@ -263,12 +263,12 @@ private void ProcessMessage(string url, ZMessage msg) poolContext.Logger.Info(() => $"External {(!string.IsNullOrEmpty(share.Source) ? $"[{share.Source.ToUpper()}] " : string.Empty)}share accepted: D={Math.Round(share.Difficulty * shareMultiplier, 3)}"); - if (pool.NetworkStats != null) + if(pool.NetworkStats != null) { - pool.NetworkStats.BlockHeight = (ulong)share.BlockHeight; + pool.NetworkStats.BlockHeight = (ulong) share.BlockHeight; pool.NetworkStats.NetworkDifficulty = share.NetworkDifficulty; - if (poolContext.BlockHeight != share.BlockHeight) + if(poolContext.BlockHeight != share.BlockHeight) { pool.NetworkStats.LastNetworkBlockTime = clock.Now; poolContext.BlockHeight = share.BlockHeight; @@ -295,7 +295,7 @@ public void Start(ClusterConfig clusterConfig) { this.clusterConfig = clusterConfig; - if (clusterConfig.ShareRelays != null) + if(clusterConfig.ShareRelays != null) { StartMessageReceiver(); StartMessageProcessors(); diff --git a/src/Miningcore/Mining/ShareRecorder.cs b/src/Miningcore/Mining/ShareRecorder.cs index 613846a10..9a111aede 100644 --- a/src/Miningcore/Mining/ShareRecorder.cs +++ b/src/Miningcore/Mining/ShareRecorder.cs @@ -113,9 +113,9 @@ await cf.RunTx(async (con, tx) => await shareRepo.BatchInsertAsync(con, tx, mapped); // Insert blocks - foreach (var share in shares) + foreach(var share in shares) { - if (!share.IsBlockCandidate) + if(!share.IsBlockCandidate) continue; var blockEntity = mapper.Map(share); @@ -148,7 +148,7 @@ private async Task OnExecutePolicyFallbackAsync(Context context, CancellationTok { using(var writer = new StreamWriter(stream, new UTF8Encoding(false))) { - if (stream.Length == 0) + if(stream.Length == 0) WriteRecoveryFileheader(writer); foreach(var share in shares) @@ -164,7 +164,7 @@ private async Task OnExecutePolicyFallbackAsync(Context context, CancellationTok catch(Exception ex) { - if (!hasLoggedPolicyFallbackFailure) + if(!hasLoggedPolicyFallbackFailure) { logger.Fatal(ex, "Fatal error during policy fallback execution. Share(s) will be lost!"); hasLoggedPolicyFallbackFailure = true; @@ -201,11 +201,11 @@ public async Task RecoverSharesAsync(ClusterConfig clusterConfig, string recover var line = reader.ReadLine().Trim(); // skip blank lines - if (line.Length == 0) + if(line.Length == 0) continue; // skip comments - if (line.StartsWith("#")) + if(line.StartsWith("#")) continue; // parse @@ -224,7 +224,7 @@ public async Task RecoverSharesAsync(ClusterConfig clusterConfig, string recover // import try { - if (shares.Count == bufferSize) + if(shares.Count == bufferSize) { await PersistSharesCoreAsync(shares); @@ -241,7 +241,7 @@ public async Task RecoverSharesAsync(ClusterConfig clusterConfig, string recover // progress var now = DateTime.UtcNow; - if (now - lastProgressUpdate > TimeSpan.FromSeconds(10)) + if(now - lastProgressUpdate > TimeSpan.FromSeconds(10)) { logger.Info($"{successCount} shares imported"); lastProgressUpdate = now; @@ -251,7 +251,7 @@ public async Task RecoverSharesAsync(ClusterConfig clusterConfig, string recover // import remaining shares try { - if (shares.Count > 0) + if(shares.Count > 0) { await PersistSharesCoreAsync(shares); @@ -267,7 +267,7 @@ public async Task RecoverSharesAsync(ClusterConfig clusterConfig, string recover } } - if (failCount == 0) + if(failCount == 0) logger.Info(() => $"Successfully imported {successCount} shares"); else logger.Warn(() => $"Successfully imported {successCount} shares with {failCount} failures"); @@ -281,7 +281,7 @@ public async Task RecoverSharesAsync(ClusterConfig clusterConfig, string recover private void NotifyAdminOnPolicyFallback() { - if (clusterConfig.Notifications?.Admin?.Enabled == true && + if(clusterConfig.Notifications?.Admin?.Enabled == true && clusterConfig.Notifications?.Admin?.NotifyPaymentSuccess == true && !notifiedAdminOnPolicyFallback) { @@ -320,7 +320,7 @@ private void StartQueue() { queueSub = messageBus.Listen() .ObserveOn(TaskPoolScheduler.Default) - .Select(x=> x.Share) + .Select(x => x.Share) .Buffer(TimeSpan.FromSeconds(5), 200) .Where(shares => shares.Any()) .Select(shares => Observable.FromAsync(async () => @@ -330,16 +330,16 @@ private void StartQueue() await PersistSharesAsync(shares); } - catch (Exception ex) + catch(Exception ex) { logger.Error(ex); } })) .Concat() .Subscribe( - _=> {}, - ex=> logger.Fatal(()=> $"{nameof(ShareRecorder)} queue terminated with {ex}"), - ()=> logger.Info(()=> $"{nameof(ShareRecorder)} queue completed")); + _ => { }, + ex => logger.Fatal(() => $"{nameof(ShareRecorder)} queue terminated with {ex}"), + () => logger.Info(() => $"{nameof(ShareRecorder)} queue completed")); } private void ConfigureRecovery() diff --git a/src/Miningcore/Mining/ShareRelay.cs b/src/Miningcore/Mining/ShareRelay.cs index 8911aeb3d..a52da60a6 100644 --- a/src/Miningcore/Mining/ShareRelay.cs +++ b/src/Miningcore/Mining/ShareRelay.cs @@ -57,7 +57,7 @@ public void Start(ClusterConfig clusterConfig) pubSocket = new ZSocket(ZSocketType.PUB); - if (!clusterConfig.ShareRelay.Connect) + if(!clusterConfig.ShareRelay.Connect) { pubSocket.SetupCurveTlsServer(clusterConfig.ShareRelay.SharedEncryptionKey, logger); @@ -111,7 +111,7 @@ private void InitializeQueue() { var flags = (int) WireFormat.ProtocolBuffers; - using (var msg = new ZMessage()) + using(var msg = new ZMessage()) { // Topic frame msg.Add(new ZFrame(share.PoolId)); @@ -139,16 +139,16 @@ private void InitializeQueue() private void CheckQueueBacklog() { - if (queue.Count > QueueSizeWarningThreshold) + if(queue.Count > QueueSizeWarningThreshold) { - if (!hasWarnedAboutBacklogSize) + if(!hasWarnedAboutBacklogSize) { logger.Warn(() => $"Share relay queue backlog has crossed {QueueSizeWarningThreshold}"); hasWarnedAboutBacklogSize = true; } } - else if (hasWarnedAboutBacklogSize && queue.Count <= QueueSizeWarningThreshold / 2) + else if(hasWarnedAboutBacklogSize && queue.Count <= QueueSizeWarningThreshold / 2) { hasWarnedAboutBacklogSize = false; } diff --git a/src/Miningcore/Mining/StatsRecorder.cs b/src/Miningcore/Mining/StatsRecorder.cs index dfd81f610..42f992939 100644 --- a/src/Miningcore/Mining/StatsRecorder.cs +++ b/src/Miningcore/Mining/StatsRecorder.cs @@ -143,12 +143,12 @@ private async Task UpdatePoolHashratesAsync() var byMiner = result.GroupBy(x => x.Miner).ToArray(); - if (result.Length > 0) + if(result.Length > 0) { // calculate pool stats var windowActual = (result.Max(x => x.LastShare) - result.Min(x => x.FirstShare)).TotalSeconds; - if (windowActual >= MinHashrateCalculationWindow) + if(windowActual >= MinHashrateCalculationWindow) { var poolHashesAccumulated = result.Sum(x => x.Sum); var poolHashesCountAccumulated = result.Sum(x => x.Count); @@ -178,7 +178,7 @@ await cf.RunTx(async (con, tx) => await statsRepo.InsertPoolStatsAsync(con, tx, mapped); }); - if (result.Length == 0) + if(result.Length == 0) continue; // calculate & update miner, worker hashrates @@ -195,7 +195,7 @@ await cf.RunTx(async (con, tx) => // calculate miner/worker stats var windowActual = (minerHashes.Max(x => x.LastShare) - minerHashes.Min(x => x.FirstShare)).TotalSeconds; - if (windowActual >= MinHashrateCalculationWindow) + if(windowActual >= MinHashrateCalculationWindow) { var hashrate = pool.HashrateFromShares(item.Sum, windowActual) * HashrateBoostFactor; minerTotalHashrate += hashrate; @@ -231,7 +231,7 @@ await cf.Run(async con => logger.Info(() => $"Deleted {rowCount} old poolstats records"); rowCount = await statsRepo.DeleteMinerStatsBeforeAsync(con, cutOff); - if (rowCount > 0) + if(rowCount > 0) logger.Info(() => $"Deleted {rowCount} old minerstats records"); }); diff --git a/src/Miningcore/Mining/WorkerContextBase.cs b/src/Miningcore/Mining/WorkerContextBase.cs index d256df99b..aefa07fe5 100644 --- a/src/Miningcore/Mining/WorkerContextBase.cs +++ b/src/Miningcore/Mining/WorkerContextBase.cs @@ -67,7 +67,7 @@ public void Init(PoolConfig poolConfig, double difficulty, VarDiffConfig varDiff LastActivity = clock.Now; Stats = new ShareStats(); - if (varDiffConfig != null) + if(varDiffConfig != null) VarDiff = new VarDiffContext { Config = varDiffConfig }; } @@ -78,7 +78,7 @@ public void EnqueueNewDifficulty(double difficulty) public bool ApplyPendingDifficulty() { - if (pendingDifficulty.HasValue) + if(pendingDifficulty.HasValue) { SetDifficulty(pendingDifficulty.Value); pendingDifficulty = null; diff --git a/src/Miningcore/Native/LibCryptonight.cs b/src/Miningcore/Native/LibCryptonight.cs index d190d033e..c1d383c05 100644 --- a/src/Miningcore/Native/LibCryptonight.cs +++ b/src/Miningcore/Native/LibCryptonight.cs @@ -40,7 +40,7 @@ internal CryptonightContextStore(Func allocator, string logId) // allocate context per CPU for(var i = 0; i < contexts.BoundedCapacity; i++) { - contexts.Add(new Lazy(()=> + contexts.Add(new Lazy(() => { var result = allocator(); @@ -57,7 +57,7 @@ internal CryptonightContextStore(Func allocator, string logId) internal Lazy Lease() { - logger.Debug(()=> $"Leasing {logId} context ({contexts.Count})"); + logger.Debug(() => $"Leasing {logId} context ({contexts.Count})"); return contexts.Take(); } @@ -148,7 +148,7 @@ public static void Cryptonight(ReadOnlySpan data, Span result, Crypt { fixed (byte* output = result) { - cryptonight(ctx.Value, input, output, (uint)data.Length, variant, height); + cryptonight(ctx.Value, input, output, (uint) data.Length, variant, height); } } } @@ -171,9 +171,9 @@ public static void CryptonightLight(ReadOnlySpan data, Span result, try { - fixed(byte* input = data) + fixed (byte* input = data) { - fixed(byte* output = result) + fixed (byte* output = result) { cryptonight_light(ctx.Value, input, output, (uint) data.Length, variant, height); } @@ -229,7 +229,7 @@ public static void CryptonightPico(ReadOnlySpan data, Span result, C { fixed (byte* output = result) { - cryptonight_pico(ctx.Value, input, output, (uint)data.Length, variant, height); + cryptonight_pico(ctx.Value, input, output, (uint) data.Length, variant, height); } } } diff --git a/src/Miningcore/Native/LibCryptonote.cs b/src/Miningcore/Native/LibCryptonote.cs index 9a1d76bd9..12709a16f 100644 --- a/src/Miningcore/Native/LibCryptonote.cs +++ b/src/Miningcore/Native/LibCryptonote.cs @@ -44,7 +44,7 @@ public static byte[] ConvertBlob(ReadOnlySpan data, int size) { Contract.Requires(data.Length > 0, $"{nameof(data)} must not be empty"); - fixed(byte* input = data) + fixed (byte* input = data) { // provide reasonable large output buffer var outputBuffer = ArrayPool.Shared.Rent(0x100); @@ -54,27 +54,27 @@ public static byte[] ConvertBlob(ReadOnlySpan data, int size) var outputBufferLength = outputBuffer.Length; var success = false; - fixed(byte* output = outputBuffer) + fixed (byte* output = outputBuffer) { success = convert_blob(input, size, output, ref outputBufferLength); } - if (!success) + if(!success) { // if we get false, the buffer might have been too small - if (outputBufferLength == 0) + if(outputBufferLength == 0) return null; // nope, other error // retry with correctly sized buffer ArrayPool.Shared.Return(outputBuffer); outputBuffer = ArrayPool.Shared.Rent(outputBufferLength); - fixed(byte* output = outputBuffer) + fixed (byte* output = outputBuffer) { success = convert_blob(input, size, output, ref outputBufferLength); } - if (!success) + if(!success) return null; // sorry } @@ -98,7 +98,7 @@ public static UInt64 DecodeAddress(string address) var data = Encoding.UTF8.GetBytes(address); - fixed(byte* input = data) + fixed (byte* input = data) { return decode_address(input, data.Length); } @@ -110,7 +110,7 @@ public static UInt64 DecodeIntegratedAddress(string address) var data = Encoding.UTF8.GetBytes(address); - fixed(byte* input = data) + fixed (byte* input = data) { return decode_integrated_address(input, data.Length); } @@ -124,7 +124,7 @@ public static void CryptonightHashFast(ReadOnlySpan data, Span resul { fixed (byte* output = result) { - cn_fast_hash(input, output, (uint)data.Length); + cn_fast_hash(input, output, (uint) data.Length); } } } diff --git a/src/Miningcore/Notifications/NotificationService.cs b/src/Miningcore/Notifications/NotificationService.cs index 2e0484590..b8bf3fc78 100644 --- a/src/Miningcore/Notifications/NotificationService.cs +++ b/src/Miningcore/Notifications/NotificationService.cs @@ -38,7 +38,7 @@ public NotificationService( adminEmail = clusterConfig.Notifications?.Admin?.EmailAddress; //adminPhone = null; - if (clusterConfig.Notifications?.Enabled == true) + if(clusterConfig.Notifications?.Enabled == true) { queue = new BlockingCollection(); @@ -74,14 +74,14 @@ public NotificationService( messageBus.Listen() .Subscribe(x => { - if (string.IsNullOrEmpty(x.Error)) + if(string.IsNullOrEmpty(x.Error)) { var coin = poolConfigs[x.PoolId].Template; // prepare tx links string[] txLinks = null; - if (!string.IsNullOrEmpty(coin.ExplorerTxLink)) + if(!string.IsNullOrEmpty(coin.ExplorerTxLink)) txLinks = x.TxIds.Select(txHash => string.Format(coin.ExplorerTxLink, txHash)).ToArray(); queue?.Add(new QueuedNotification @@ -150,19 +150,19 @@ private async Task SendNotificationAsync(QueuedNotification notification) switch(notification.Category) { case NotificationCategory.Admin: - if (clusterConfig.Notifications?.Admin?.Enabled == true) + if(clusterConfig.Notifications?.Admin?.Enabled == true) await SendEmailAsync(adminEmail, notification.Subject, notification.Msg); break; case NotificationCategory.Block: - if (clusterConfig.Notifications?.Admin?.Enabled == true && + if(clusterConfig.Notifications?.Admin?.Enabled == true && clusterConfig.Notifications?.Admin?.NotifyBlockFound == true) await SendEmailAsync(adminEmail, notification.Subject, notification.Msg); break; case NotificationCategory.PaymentSuccess: case NotificationCategory.PaymentFailure: - if (clusterConfig.Notifications?.Admin?.Enabled == true && + if(clusterConfig.Notifications?.Admin?.Enabled == true && clusterConfig.Notifications?.Admin?.NotifyPaymentSuccess == true) await SendEmailAsync(adminEmail, notification.Subject, notification.Msg); break; diff --git a/src/Miningcore/Payments/PaymentSchemes/PPLNSPaymentScheme.cs b/src/Miningcore/Payments/PaymentSchemes/PPLNSPaymentScheme.cs index c8c45f727..de65cc247 100644 --- a/src/Miningcore/Payments/PaymentSchemes/PPLNSPaymentScheme.cs +++ b/src/Miningcore/Payments/PaymentSchemes/PPLNSPaymentScheme.cs @@ -95,7 +95,7 @@ public async Task UpdateBalancesAsync(IDbConnection con, IDbTransaction tx, Pool { var amount = rewards[address]; - if (amount > 0) + if(amount > 0) { logger.Info(() => $"Adding {payoutHandler.FormatAmount(amount)} to balance of {address} for {FormatUtil.FormatQuantity(shares[address])} ({shares[address]}) shares for block {block.BlockHeight}"); await balanceRepo.AddAmountAsync(con, tx, poolConfig.Id, address, amount, $"Reward for {FormatUtil.FormatQuantity(shares[address])} shares for block {block.BlockHeight}"); @@ -103,11 +103,11 @@ public async Task UpdateBalancesAsync(IDbConnection con, IDbTransaction tx, Pool } // delete discarded shares - if (shareCutOffDate.HasValue) + if(shareCutOffDate.HasValue) { var cutOffCount = await shareRepo.CountSharesBeforeCreatedAsync(con, tx, poolConfig.Id, shareCutOffDate.Value); - if (cutOffCount > 0) + if(cutOffCount > 0) { await LogDiscardedSharesAsync(poolConfig, block, shareCutOffDate.Value); @@ -122,7 +122,7 @@ public async Task UpdateBalancesAsync(IDbConnection con, IDbTransaction tx, Pool var totalShareCount = shares.Values.ToList().Sum(x => new decimal(x)); var totalRewards = rewards.Values.ToList().Sum(x => x); - if (totalRewards > 0) + if(totalRewards > 0) logger.Info(() => $"{FormatUtil.FormatQuantity((double) totalShareCount)} ({Math.Round(totalShareCount, 2)}) shares contributed to a total payout of {payoutHandler.FormatAmount(totalRewards)} ({totalRewards / blockReward * 100:0.00}% of block reward) to {rewards.Keys.Count} addresses"); } @@ -148,19 +148,19 @@ private async Task LogDiscardedSharesAsync(PoolConfig poolConfig, Block block, D var address = share.Miner; // record attributed shares for diagnostic purposes - if (!shares.ContainsKey(address)) + if(!shares.ContainsKey(address)) shares[address] = share.Difficulty; else shares[address] += share.Difficulty; } - if (page.Length < pageSize) + if(page.Length < pageSize) break; before = page[page.Length - 1].Created; } - if (shares.Keys.Count > 0) + if(shares.Keys.Count > 0) { // sort addresses by shares var addressesByShares = shares.Keys.OrderByDescending(x => shares[x]); @@ -205,7 +205,7 @@ private async Task LogDiscardedSharesAsync(PoolConfig poolConfig, Block block, D var address = share.Miner; // record attributed shares for diagnostic purposes - if (!shares.ContainsKey(address)) + if(!shares.ContainsKey(address)) shares[address] = share.Difficulty; else shares[address] += share.Difficulty; @@ -213,7 +213,7 @@ private async Task LogDiscardedSharesAsync(PoolConfig poolConfig, Block block, D var score = (decimal) (share.Difficulty / share.NetworkDifficulty); // if accumulated score would cross threshold, cap it to the remaining value - if (accumulatedScore + score >= window) + if(accumulatedScore + score >= window) { score = window - accumulatedScore; shareCutOffDate = share.Created; @@ -226,20 +226,20 @@ private async Task LogDiscardedSharesAsync(PoolConfig poolConfig, Block block, D blockRewardRemaining -= reward; // this should never happen - if (blockRewardRemaining <= 0 && !done) + if(blockRewardRemaining <= 0 && !done) throw new OverflowException("blockRewardRemaining < 0"); - if (reward > 0) + if(reward > 0) { // accumulate miner reward - if (!rewards.ContainsKey(address)) + if(!rewards.ContainsKey(address)) rewards[address] = reward; else rewards[address] += reward; } } - if (page.Length < pageSize) + if(page.Length < pageSize) break; before = page[page.Length - 1].Created; diff --git a/src/Miningcore/Payments/PaymentSchemes/SoloPaymentScheme.cs b/src/Miningcore/Payments/PaymentSchemes/SoloPaymentScheme.cs index f97c4cd61..167c52d70 100644 --- a/src/Miningcore/Payments/PaymentSchemes/SoloPaymentScheme.cs +++ b/src/Miningcore/Payments/PaymentSchemes/SoloPaymentScheme.cs @@ -79,7 +79,7 @@ public async Task UpdateBalancesAsync(IDbConnection con, IDbTransaction tx, Pool { var amount = rewards[address]; - if (amount > 0) + if(amount > 0) { logger.Info(() => $"Adding {payoutHandler.FormatAmount(amount)} to balance of {address} for block {block.BlockHeight}"); await balanceRepo.AddAmountAsync(con, tx, poolConfig.Id, address, amount, $"Reward for block {block.BlockHeight}"); @@ -87,11 +87,11 @@ public async Task UpdateBalancesAsync(IDbConnection con, IDbTransaction tx, Pool } // delete discarded shares - if (shareCutOffDate.HasValue) + if(shareCutOffDate.HasValue) { var cutOffCount = await shareRepo.CountSharesBeforeCreatedAsync(con, tx, poolConfig.Id, shareCutOffDate.Value); - if (cutOffCount > 0) + if(cutOffCount > 0) { #if !DEBUG logger.Info(() => $"Deleting {cutOffCount} discarded shares before {shareCutOffDate.Value:O}"); @@ -111,7 +111,7 @@ public async Task UpdateBalancesAsync(IDbConnection con, IDbTransaction tx, Pool .Select(x => x.Address) .ToArray(); - if (recipients.Length == 0) + if(recipients.Length == 0) throw new Exception("No reward-recipients of type = 'solo' configured"); // split reward evenly between configured solo-recipients diff --git a/src/Miningcore/Payments/PayoutHandlerBase.cs b/src/Miningcore/Payments/PayoutHandlerBase.cs index 820dbe40e..14add42db 100644 --- a/src/Miningcore/Payments/PayoutHandlerBase.cs +++ b/src/Miningcore/Payments/PayoutHandlerBase.cs @@ -110,7 +110,7 @@ public virtual async Task UpdateBlockRewardBalancesAsync(IDbConnection var blockRewardRemaining = block.Reward; // Distribute funds to configured reward recipients - foreach (var recipient in poolConfig.RewardRecipients.Where(x => x.Percentage > 0)) + foreach(var recipient in poolConfig.RewardRecipients.Where(x => x.Percentage > 0)) { var amount = block.Reward * (recipient.Percentage / 100.0m); var address = recipient.Address; @@ -118,7 +118,7 @@ public virtual async Task UpdateBlockRewardBalancesAsync(IDbConnection blockRewardRemaining -= amount; // skip transfers from pool wallet to pool wallet - if (address != poolConfig.Address) + if(address != poolConfig.Address) { logger.Info(() => $"Adding {FormatAmount(amount)} to balance of {address}"); await balanceRepo.AddAmountAsync(con, tx, poolConfig.Id, address, amount, $"Reward for block {block.BlockHeight}"); @@ -140,7 +140,7 @@ await cf.RunTx(async (con, tx) => { foreach(var balance in balances) { - if (!string.IsNullOrEmpty(transactionConfirmation) && + if(!string.IsNullOrEmpty(transactionConfirmation) && !poolConfig.RewardRecipients.Any(x => x.Address == balance.Address)) { // record payment diff --git a/src/Miningcore/Payments/PayoutManager.cs b/src/Miningcore/Payments/PayoutManager.cs index bde33cb3a..b0b11842b 100644 --- a/src/Miningcore/Payments/PayoutManager.cs +++ b/src/Miningcore/Payments/PayoutManager.cs @@ -100,14 +100,14 @@ private async Task ProcessPoolsAsync() await PayoutPoolBalancesAsync(pool, handler); } - catch (InvalidOperationException ex) + catch(InvalidOperationException ex) { logger.Error(ex.InnerException ?? ex, () => $"[{pool.Id}] Payment processing failed"); } - catch (AggregateException ex) + catch(AggregateException ex) { - switch (ex.InnerException) + switch(ex.InnerException) { case HttpRequestException httpEx: logger.Error(() => $"[{pool.Id}] Payment processing failed: {httpEx.Message}"); @@ -119,7 +119,7 @@ private async Task ProcessPoolsAsync() } } - catch (Exception ex) + catch(Exception ex) { logger.Error(ex, () => $"[{pool.Id}] Payment processing failed"); } @@ -133,7 +133,7 @@ private static CoinFamily HandleFamilyOverride(CoinFamily family, PoolConfig poo case CoinFamily.Equihash: var equihashTemplate = pool.Template.As(); - if (equihashTemplate.UseBitcoinPayoutHandler) + if(equihashTemplate.UseBitcoinPayoutHandler) return CoinFamily.Bitcoin; break; @@ -150,7 +150,7 @@ private async Task UpdatePoolBalancesAsync(PoolConfig pool, IPayoutHandler handl // classify var updatedBlocks = await handler.ClassifyBlocksAsync(pendingBlocks); - if (updatedBlocks.Any()) + if(updatedBlocks.Any()) { foreach(var block in updatedBlocks.OrderBy(x => x.Created)) { @@ -158,10 +158,10 @@ private async Task UpdatePoolBalancesAsync(PoolConfig pool, IPayoutHandler handl await cf.RunTx(async (con, tx) => { - if (!block.Effort.HasValue) // fill block effort if empty + if(!block.Effort.HasValue) // fill block effort if empty await CalculateBlockEffortAsync(pool, block, handler); - switch (block.Status) + switch(block.Status) { case BlockStatus.Confirmed: // blockchains that do not support block-reward payments via coinbase Tx @@ -190,7 +190,7 @@ private async Task PayoutPoolBalancesAsync(PoolConfig pool, IPayoutHandler handl var poolBalancesOverMinimum = await cf.Run(con => balanceRepo.GetPoolBalancesOverThresholdAsync(con, pool.Id, pool.PaymentProcessing.MinimumPayment)); - if (poolBalancesOverMinimum.Length > 0) + if(poolBalancesOverMinimum.Length > 0) { try { @@ -229,7 +229,7 @@ private async Task CalculateBlockEffortAsync(PoolConfig pool, Block block, IPayo BlockStatus.Pending, }, block.Created)); - if (lastBlock != null) + if(lastBlock != null) from = lastBlock.Created; // get combined diff of all shares for block @@ -237,7 +237,7 @@ private async Task CalculateBlockEffortAsync(PoolConfig pool, Block block, IPayo shareRepo.GetAccumulatedShareDifficultyBetweenCreatedAsync(con, pool.Id, from, to)); // handler has the final say - if (accumulatedShareDiffForBlock.HasValue) + if(accumulatedShareDiffForBlock.HasValue) await handler.CalculateBlockEffortAsync(block, accumulatedShareDiffForBlock.Value); } @@ -247,7 +247,7 @@ public void Configure(ClusterConfig clusterConfig) { this.clusterConfig = clusterConfig; - interval = TimeSpan.FromSeconds(clusterConfig.PaymentProcessing.Interval > 0 ? + interval = TimeSpan.FromSeconds(clusterConfig.PaymentProcessing.Interval > 0 ? clusterConfig.PaymentProcessing.Interval : 600); } @@ -257,7 +257,7 @@ public void Start() { logger.Info(() => "Online"); - while (!cts.IsCancellationRequested) + while(!cts.IsCancellationRequested) { try { diff --git a/src/Miningcore/Persistence/Postgres/Repositories/BalanceRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/BalanceRepository.cs index bb03c20c7..96dc1316a 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/BalanceRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/BalanceRepository.cs @@ -68,7 +68,7 @@ public async Task AddAmountAsync(IDbConnection con, IDbTransaction tx, stri var balance = (await con.QueryAsync(query, new { poolId, address }, tx)) .FirstOrDefault(); - if (balance == null) + if(balance == null) { balance = new Entities.Balance { diff --git a/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs index 11d646d57..eb855c795 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs @@ -81,12 +81,12 @@ public async Task PageBlocksAsync(IDbConnection con, string poolId, Blo "ORDER BY created DESC OFFSET @offset FETCH NEXT (@pageSize) ROWS ONLY"; return (await con.QueryAsync(query, new - { - poolId, - status = status.Select(x => x.ToString().ToLower()).ToArray(), - offset = page * pageSize, - pageSize - })) + { + poolId, + status = status.Select(x => x.ToString().ToLower()).ToArray(), + offset = page * pageSize, + pageSize + })) .Select(mapper.Map) .ToArray(); } @@ -125,11 +125,11 @@ public async Task GetBlockBeforeAsync(IDbConnection con, string poolId, B "ORDER BY created DESC FETCH NEXT (1) ROWS ONLY"; return (await con.QueryAsync(query, new - { - poolId, - before, - status = status.Select(x => x.ToString().ToLower()).ToArray() - })) + { + poolId, + before, + status = status.Select(x => x.ToString().ToLower()).ToArray() + })) .Select(mapper.Map) .FirstOrDefault(); } diff --git a/src/Miningcore/Persistence/Postgres/Repositories/PaymentRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/PaymentRepository.cs index 9df257711..43b9b8fe1 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/PaymentRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/PaymentRepository.cs @@ -59,7 +59,7 @@ public async Task PagePaymentsAsync(IDbConnection con, string poolId, var query = "SELECT * FROM payments WHERE poolid = @poolid "; - if (!string.IsNullOrEmpty(address)) + if(!string.IsNullOrEmpty(address)) query += " AND address = @address "; query += "ORDER BY created DESC OFFSET @offset FETCH NEXT (@pageSize) ROWS ONLY"; diff --git a/src/Miningcore/Persistence/Postgres/Repositories/ShareRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/ShareRepository.cs index 9b9362731..664869394 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/ShareRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/ShareRepository.cs @@ -67,14 +67,14 @@ public Task BatchInsertAsync(IDbConnection con, IDbTransaction tx, IEnumerable CountSharesBetweenCreatedAsync(IDbConnection con, string poolI var whereClause = "poolid = @poolId AND miner = @miner"; - if (start.HasValue) + if(start.HasValue) whereClause += " AND created >= @start "; - if (end.HasValue) + if(end.HasValue) whereClause += " AND created <= @end"; var query = $"SELECT count(*) FROM shares WHERE {whereClause}"; diff --git a/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs index ddf253d59..8a6edd5ac 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs @@ -67,7 +67,7 @@ public async Task InsertMinerWorkerPerformanceStatsAsync(IDbConnection con, IDbT var mapped = mapper.Map(stats); - if (string.IsNullOrEmpty(mapped.Worker)) + if(string.IsNullOrEmpty(mapped.Worker)) mapped.Worker = string.Empty; const string query = "INSERT INTO minerstats(poolid, miner, worker, hashrate, sharespersecond, created) " + @@ -83,7 +83,7 @@ public async Task GetLastPoolStatsAsync(IDbConnection con, string poo const string query = "SELECT * FROM poolstats WHERE poolid = @poolId ORDER BY created DESC FETCH NEXT 1 ROWS ONLY"; var entity = await con.QuerySingleOrDefaultAsync(query, new { poolId }); - if (entity == null) + if(entity == null) return null; return mapper.Map(entity); @@ -139,7 +139,7 @@ public async Task GetMinerStatsAsync(IDbConnection con, IDbTransacti var result = await con.QuerySingleOrDefaultAsync(query, new { poolId, miner }, tx); - if (result != null) + if(result != null) { query = "SELECT * FROM payments WHERE poolid = @poolId AND address = @miner" + " ORDER BY created DESC LIMIT 1"; @@ -153,10 +153,10 @@ public async Task GetMinerStatsAsync(IDbConnection con, IDbTransacti var lastUpdate = await con.QuerySingleOrDefaultAsync(query, new { poolId, miner }, tx); // ignore stale minerstats - if (lastUpdate.HasValue && (clock.Now - DateTime.SpecifyKind(lastUpdate.Value, DateTimeKind.Utc) > MinerStatsMaxAge)) + if(lastUpdate.HasValue && (clock.Now - DateTime.SpecifyKind(lastUpdate.Value, DateTimeKind.Utc) > MinerStatsMaxAge)) lastUpdate = null; - if (lastUpdate.HasValue) + if(lastUpdate.HasValue) { // load rows rows by timestamp query = "SELECT * FROM minerstats WHERE poolid = @poolId AND miner = @miner AND created = @created"; @@ -165,12 +165,12 @@ public async Task GetMinerStatsAsync(IDbConnection con, IDbTransacti .Select(mapper.Map) .ToArray(); - if (stats.Any()) + if(stats.Any()) { // replace null worker with empty string foreach(var stat in stats) { - if (stat.Worker == null) + if(stat.Worker == null) { stat.Worker = string.Empty; break; @@ -217,14 +217,14 @@ public async Task GetMinerPerformanceBetweenH .GroupBy(x => x.Created); var tmp = entitiesByDate.Select(x => new WorkerPerformanceStatsContainer + { + Created = x.Key, + Workers = x.ToDictionary(y => y.Worker ?? string.Empty, y => new WorkerPerformanceStats { - Created = x.Key, - Workers = x.ToDictionary(y => y.Worker ?? string.Empty, y => new WorkerPerformanceStats - { - Hashrate = y.Hashrate, - SharesPerSecond = y.SharesPerSecond - }) + Hashrate = y.Hashrate, + SharesPerSecond = y.SharesPerSecond }) + }) .ToArray(); //.ToDictionary(x=> x.Created.ToUniversalTime().ToUnixTimestamp(), x=> x); @@ -260,14 +260,14 @@ public async Task GetMinerPerformanceBetweenD .GroupBy(x => x.Created); var tmp = entitiesByDate.Select(x => new WorkerPerformanceStatsContainer + { + Created = x.Key, + Workers = x.ToDictionary(y => y.Worker, y => new WorkerPerformanceStats { - Created = x.Key, - Workers = x.ToDictionary(y => y.Worker, y => new WorkerPerformanceStats - { - Hashrate = y.Hashrate, - SharesPerSecond = y.SharesPerSecond - }) + Hashrate = y.Hashrate, + SharesPerSecond = y.SharesPerSecond }) + }) .ToArray(); //.ToDictionary(x => x.Created.ToUniversalTime().ToUnixTimestamp(), x => x); diff --git a/src/Miningcore/Program.cs b/src/Miningcore/Program.cs index a59b456ab..691e1689b 100644 --- a/src/Miningcore/Program.cs +++ b/src/Miningcore/Program.cs @@ -110,7 +110,7 @@ public static void Main(string[] args) AppDomain.CurrentDomain.ProcessExit += OnProcessExit; Console.CancelKeyPress += OnCancelKeyPress; - if (!HandleCommandLineOptions(args, out var configFile)) + if(!HandleCommandLineOptions(args, out var configFile)) return; isShareRecoveryMode = shareRecoveryOption.HasValue(); @@ -118,7 +118,7 @@ public static void Main(string[] args) Logo(); clusterConfig = ReadConfig(configFile); - if (dumpConfigOption.HasValue()) + if(dumpConfigOption.HasValue()) { DumpParsedConfig(clusterConfig); return; @@ -128,9 +128,9 @@ public static void Main(string[] args) Bootstrap(); LogRuntimeInfo(); - if (!isShareRecoveryMode) + if(!isShareRecoveryMode) { - if (!cts.IsCancellationRequested) + if(!cts.IsCancellationRequested) Start().Wait(cts.Token); } @@ -140,7 +140,7 @@ public static void Main(string[] args) catch(PoolStartupAbortException ex) { - if (!string.IsNullOrEmpty(ex.Message)) + if(!string.IsNullOrEmpty(ex.Message)) Console.WriteLine(ex.Message); Console.WriteLine("\nCluster cannot start. Good Bye!"); @@ -158,7 +158,7 @@ public static void Main(string[] args) catch(AggregateException ex) { - if (!(ex.InnerExceptions.First() is PoolStartupAbortException)) + if(!(ex.InnerExceptions.First() is PoolStartupAbortException)) Console.WriteLine(ex); Console.WriteLine("Cluster cannot start. Good Bye!"); @@ -191,7 +191,7 @@ private static void ValidateConfig() // set some defaults foreach(var config in clusterConfig.Pools) { - if (!config.EnableInternalStratum.HasValue) + if(!config.EnableInternalStratum.HasValue) config.EnableInternalStratum = clusterConfig.ShareRelays == null || clusterConfig.ShareRelays.Length == 0; } @@ -241,13 +241,13 @@ private static bool HandleCommandLineOptions(string[] args, out string configFil app.Execute(args); - if (versionOption.HasValue()) + if(versionOption.HasValue()) { app.ShowVersion(); return false; } - if (!configFileOption.HasValue()) + if(!configFileOption.HasValue()) { app.ShowHelp(); return false; @@ -325,14 +325,14 @@ private static void HumanizeJsonParseException(JsonSerializationException ex) { var m = regexJsonTypeConversionError.Match(ex.Message); - if (m.Success) + if(m.Success) { var value = m.Groups[1].Value; var type = Type.GetType(m.Groups[2].Value); var line = m.Groups[3].Value; var col = m.Groups[4].Value; - if (type == typeof(PayoutScheme)) + if(type == typeof(PayoutScheme)) Console.WriteLine($"Error: Payout scheme '{value}' is not (yet) supported (line {line}, column {col})"); } @@ -345,11 +345,11 @@ private static void HumanizeJsonParseException(JsonSerializationException ex) private static void ValidateRuntimeEnvironment() { // root check - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && Environment.UserName == "root") + if(!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && Environment.UserName == "root") logger.Warn(() => "Running as root is discouraged!"); // require 64-bit on Windows - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && RuntimeInformation.ProcessArchitecture == Architecture.X86) + if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && RuntimeInformation.ProcessArchitecture == Architecture.X86) throw new PoolStartupAbortException("Miningcore requires 64-Bit Windows"); } @@ -362,7 +362,7 @@ private static void MonitorGc() while(true) { var s = GC.WaitForFullGCApproach(); - if (s == GCNotificationStatus.Succeeded) + if(s == GCNotificationStatus.Succeeded) { logger.Info(() => "FullGC soon"); sw.Start(); @@ -370,13 +370,13 @@ private static void MonitorGc() s = GC.WaitForFullGCComplete(); - if (s == GCNotificationStatus.Succeeded) + if(s == GCNotificationStatus.Succeeded) { logger.Info(() => "FullGC completed"); sw.Stop(); - if (sw.Elapsed.TotalSeconds > gcStats.MaxFullGcDuration) + if(sw.Elapsed.TotalSeconds > gcStats.MaxFullGcDuration) gcStats.MaxFullGcDuration = sw.Elapsed.TotalSeconds; sw.Reset(); @@ -415,7 +415,7 @@ private static void ConfigureLogging() var config = clusterConfig.Logging; var loggingConfig = new LoggingConfiguration(); - if (config != null) + if(config != null) { // parse level var level = !string.IsNullOrEmpty(config.Level) @@ -435,7 +435,7 @@ private static void ConfigureLogging() loggingConfig.AddRule(level, LogLevel.Info, nullTarget, "Microsoft.AspNetCore.Mvc.Infrastructure.*", true); // Api Log - if (!string.IsNullOrEmpty(config.ApiLogFile) && !isShareRecoveryMode) + if(!string.IsNullOrEmpty(config.ApiLogFile) && !isShareRecoveryMode) { var target = new FileTarget("file") { @@ -448,9 +448,9 @@ private static void ConfigureLogging() loggingConfig.AddRule(level, LogLevel.Fatal, target, "Microsoft.AspNetCore.*", true); } - if (config.EnableConsoleLog || isShareRecoveryMode) + if(config.EnableConsoleLog || isShareRecoveryMode) { - if (config.EnableConsoleColors) + if(config.EnableConsoleColors) { var target = new ColoredConsoleTarget("console") { @@ -497,7 +497,7 @@ private static void ConfigureLogging() } } - if (!string.IsNullOrEmpty(config.LogFile) && !isShareRecoveryMode) + if(!string.IsNullOrEmpty(config.LogFile) && !isShareRecoveryMode) { var target = new FileTarget("file") { @@ -510,7 +510,7 @@ private static void ConfigureLogging() loggingConfig.AddRule(level, LogLevel.Fatal, target); } - if (config.PerPoolLogFile && !isShareRecoveryMode) + if(config.PerPoolLogFile && !isShareRecoveryMode) { foreach(var poolConfig in clusterConfig.Pools) { @@ -534,7 +534,7 @@ private static void ConfigureLogging() private static Layout GetLogPath(ClusterLoggingConfig config, string name) { - if (string.IsNullOrEmpty(config.LogBaseDirectory)) + if(string.IsNullOrEmpty(config.LogBaseDirectory)) return name; return Path.Combine(config.LogBaseDirectory, name); @@ -543,18 +543,18 @@ private static Layout GetLogPath(ClusterLoggingConfig config, string name) private static void ConfigureMisc() { // Configure Equihash - if (clusterConfig.EquihashMaxThreads.HasValue) + if(clusterConfig.EquihashMaxThreads.HasValue) EquihashSolver.MaxThreads = clusterConfig.EquihashMaxThreads.Value; } private static void ConfigurePersistence(ContainerBuilder builder) { - if (clusterConfig.Persistence == null && + if(clusterConfig.Persistence == null && clusterConfig.PaymentProcessing?.Enabled == true && clusterConfig.ShareRelay == null) logger.ThrowLogPoolStartupException("Persistence is not configured!"); - if (clusterConfig.Persistence?.Postgres != null) + if(clusterConfig.Persistence?.Postgres != null) ConfigurePostgres(clusterConfig.Persistence.Postgres, builder); else ConfigureDummyPersistence(builder); @@ -563,16 +563,16 @@ private static void ConfigurePersistence(ContainerBuilder builder) private static void ConfigurePostgres(DatabaseConfig pgConfig, ContainerBuilder builder) { // validate config - if (string.IsNullOrEmpty(pgConfig.Host)) + if(string.IsNullOrEmpty(pgConfig.Host)) logger.ThrowLogPoolStartupException("Postgres configuration: invalid or missing 'host'"); - if (pgConfig.Port == 0) + if(pgConfig.Port == 0) logger.ThrowLogPoolStartupException("Postgres configuration: invalid or missing 'port'"); - if (string.IsNullOrEmpty(pgConfig.Database)) + if(string.IsNullOrEmpty(pgConfig.Database)) logger.ThrowLogPoolStartupException("Postgres configuration: invalid or missing 'database'"); - if (string.IsNullOrEmpty(pgConfig.User)) + if(string.IsNullOrEmpty(pgConfig.User)) logger.ThrowLogPoolStartupException("Postgres configuration: invalid or missing 'user'"); // build connection string @@ -625,20 +625,20 @@ private static Dictionary LoadCoinTemplates() private static void UseIpWhiteList(IApplicationBuilder app, bool defaultToLoopback, string[] locations, string[] whitelist) { var ipList = whitelist?.Select(x => IPAddress.Parse(x)).ToList(); - if (defaultToLoopback && (ipList == null || ipList.Count == 0)) + if(defaultToLoopback && (ipList == null || ipList.Count == 0)) ipList = new List(new[] { IPAddress.Loopback, IPAddress.IPv6Loopback, IPUtils.IPv4LoopBackOnIPv6 }); - if (ipList.Count > 0) + if(ipList.Count > 0) { // always allow access by localhost - if (!ipList.Any(x => x.Equals(IPAddress.Loopback))) + if(!ipList.Any(x => x.Equals(IPAddress.Loopback))) ipList.Add(IPAddress.Loopback); - if (!ipList.Any(x => x.Equals(IPAddress.IPv6Loopback))) + if(!ipList.Any(x => x.Equals(IPAddress.IPv6Loopback))) ipList.Add(IPAddress.IPv6Loopback); - if (!ipList.Any(x => x.Equals(IPUtils.IPv4LoopBackOnIPv6))) + if(!ipList.Any(x => x.Equals(IPUtils.IPv4LoopBackOnIPv6))) ipList.Add(IPUtils.IPv4LoopBackOnIPv6); - logger.Info(() => $"API Access to {string.Join(",", locations)} restricted to {string.Join(",", ipList.Select(x=> x.ToString()))}"); + logger.Info(() => $"API Access to {string.Join(",", locations)} restricted to {string.Join(",", ipList.Select(x => x.ToString()))}"); app.UseMiddleware(locations, ipList.ToArray()); } @@ -659,7 +659,7 @@ private static void ConfigureIpRateLimitOptions(IpRateLimitOptions options) options.IpWhitelist = clusterConfig.Api?.RateLimiting?.IpWhitelist?.ToList(); // default to whitelist localhost if whitelist absent - if (options.IpWhitelist == null || options.IpWhitelist.Count == 0) + if(options.IpWhitelist == null || options.IpWhitelist.Count == 0) { options.IpWhitelist = new List { @@ -672,7 +672,7 @@ private static void ConfigureIpRateLimitOptions(IpRateLimitOptions options) // limits var rules = clusterConfig.Api?.RateLimiting?.Rules?.ToList(); - if (rules == null || rules.Count == 0) + if(rules == null || rules.Count == 0) { rules = new List { @@ -711,7 +711,7 @@ private static void StartApi() .ConfigureServices(services => { // rate limiting - if (enableApiRateLimiting) + if(enableApiRateLimiting) { services.Configure(ConfigureIpRateLimitOptions); services.AddSingleton(); @@ -724,7 +724,7 @@ private static void StartApi() services.AddSingleton(); // MVC - services.AddSingleton((IComponentContext)container); + services.AddSingleton((IComponentContext) container); services.AddSingleton(); services.AddMvc() @@ -743,7 +743,7 @@ private static void StartApi() }) .Configure(app => { - if (enableApiRateLimiting) + if(enableApiRateLimiting) app.UseIpRateLimiting(); app.UseMiddleware(); @@ -773,10 +773,10 @@ private static async Task Start() logger.Info($"{coinTemplates.Keys.Count} coins loaded from {string.Join(", ", clusterConfig.CoinTemplates)}"); // Populate pool configs with corresponding template - foreach (var poolConfig in clusterConfig.Pools.Where(x => x.Enabled)) + foreach(var poolConfig in clusterConfig.Pools.Where(x => x.Enabled)) { // Lookup coin definition - if (!coinTemplates.TryGetValue(poolConfig.Coin, out var template)) + if(!coinTemplates.TryGetValue(poolConfig.Coin, out var template)) logger.ThrowLogPoolStartupException($"Pool {poolConfig.Id} references undefined coin '{poolConfig.Coin}'"); poolConfig.Template = template; @@ -789,7 +789,7 @@ private static async Task Start() btStreamReceiver = container.Resolve(); btStreamReceiver.Start(clusterConfig); - if (clusterConfig.ShareRelay == null) + if(clusterConfig.ShareRelay == null) { // start share recorder shareRecorder = container.Resolve(); @@ -808,7 +808,7 @@ private static async Task Start() } // start API - if (clusterConfig.Api == null || clusterConfig.Api.Enabled) + if(clusterConfig.Api == null || clusterConfig.Api.Enabled) { StartApi(); @@ -816,7 +816,7 @@ private static async Task Start() } // start payment processor - if (clusterConfig.PaymentProcessing?.Enabled == true && + if(clusterConfig.PaymentProcessing?.Enabled == true && clusterConfig.Pools.Any(x => x.PaymentProcessing?.Enabled == true)) { payoutManager = container.Resolve(); @@ -828,7 +828,7 @@ private static async Task Start() else logger.Info("Payment processing is not enabled"); - if (clusterConfig.ShareRelay == null) + if(clusterConfig.ShareRelay == null) { // start pool stats updater statsRecorder = container.Resolve(); @@ -868,7 +868,7 @@ private static Task RecoverSharesAsync(string recoveryFilename) private static void OnAppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e) { - if (logger != null) + if(logger != null) { logger.Error(e.ExceptionObject); LogManager.Flush(TimeSpan.Zero); diff --git a/src/Miningcore/Serialization/HexToByteArrayJsonConverter.cs b/src/Miningcore/Serialization/HexToByteArrayJsonConverter.cs index 494ca979b..cae7f0f1d 100644 --- a/src/Miningcore/Serialization/HexToByteArrayJsonConverter.cs +++ b/src/Miningcore/Serialization/HexToByteArrayJsonConverter.cs @@ -20,10 +20,10 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var str = (string) reader.Value; - if (str.StartsWith("0x")) + if(str.StartsWith("0x")) str = str.Substring(2); - if (string.IsNullOrEmpty(str)) + if(string.IsNullOrEmpty(str)) return null; return str.HexToByteArray(); diff --git a/src/Miningcore/Serialization/HexToIntegralTypeJsonConverter.cs b/src/Miningcore/Serialization/HexToIntegralTypeJsonConverter.cs index c00ab8406..f86d8b3a9 100644 --- a/src/Miningcore/Serialization/HexToIntegralTypeJsonConverter.cs +++ b/src/Miningcore/Serialization/HexToIntegralTypeJsonConverter.cs @@ -18,7 +18,7 @@ public override bool CanConvert(Type objectType) public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - if (value == null) + if(value == null) writer.WriteValue("null"); else writer.WriteValue($"0x{value:x}"); @@ -28,16 +28,16 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist { var str = (string) reader.Value; - if (string.IsNullOrEmpty(str)) + if(string.IsNullOrEmpty(str)) return default(T); - if (str.StartsWith("0x")) + if(str.StartsWith("0x")) str = str.Substring(2); - if (typeof(T) == typeof(BigInteger)) + if(typeof(T) == typeof(BigInteger)) return BigInteger.Parse("0" + str, NumberStyles.HexNumber); - if (typeof(T) == typeof(uint256)) + if(typeof(T) == typeof(uint256)) return new uint256(str.HexToReverseByteArray()); var val = ulong.Parse("0" + str, NumberStyles.HexNumber, CultureInfo.InvariantCulture); diff --git a/src/Miningcore/Stratum/StratumClient.cs b/src/Miningcore/Stratum/StratumClient.cs index d559540de..89368de93 100644 --- a/src/Miningcore/Stratum/StratumClient.cs +++ b/src/Miningcore/Stratum/StratumClient.cs @@ -105,7 +105,7 @@ public void Run(Socket socket, Action onError) { PoolEndpoint = endpoint.IPEndPoint; - RemoteEndpoint = (IPEndPoint)socket.RemoteEndPoint; + RemoteEndpoint = (IPEndPoint) socket.RemoteEndPoint; expectingProxyHeader = endpoint.PoolEndpoint.TcpProxyProtocol?.Enable == true; @@ -121,9 +121,9 @@ public void Run(Socket socket, networkStream = new NetworkStream(socket, true); logger.Info(() => $"[{ConnectionId}] Accepting connection from {RemoteEndpoint.Address}:{RemoteEndpoint.Port} ..."); - using (var disposables = new CompositeDisposable(networkStream, cts)) + using(var disposables = new CompositeDisposable(networkStream, cts)) { - if (endpoint.PoolEndpoint.Tls) + if(endpoint.PoolEndpoint.Tls) { var sslStream = new SslStream(networkStream, false); disposables.Add(sslStream); @@ -159,14 +159,14 @@ public void Run(Socket socket, // Signal completion or error var error = tasks.FirstOrDefault(t => t.IsFaulted)?.Exception; - if (error == null) + if(error == null) onCompleted(this); else onError(this, error); } } - catch (Exception ex) + catch(Exception ex) { onError(this, ex); } @@ -196,7 +196,7 @@ public void SetContext(T value) where T : WorkerContextBase public T ContextAs() where T : WorkerContextBase { - return (T)context; + return (T) context; } public ValueTask RespondAsync(T payload, object id) @@ -206,7 +206,7 @@ public ValueTask RespondAsync(T payload, object id) public ValueTask RespondErrorAsync(StratumError code, string message, object id, object result = null, object data = null) { - return RespondAsync(new JsonRpcResponse(new JsonRpcException((int)code, message, null), id, result)); + return RespondAsync(new JsonRpcResponse(new JsonRpcException((int) code, message, null), id, result)); } public ValueTask RespondAsync(JsonRpcResponse response) @@ -235,13 +235,13 @@ private async ValueTask SendAsync(T payload) { Contract.RequiresNonNull(payload, nameof(payload)); - using (var ctsTimeout = new CancellationTokenSource()) + using(var ctsTimeout = new CancellationTokenSource()) { - using (var ctsComposite = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, ctsTimeout.Token)) + using(var ctsComposite = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, ctsTimeout.Token)) { ctsTimeout.CancelAfter(sendTimeout); - if (!await sendQueue.SendAsync(payload, ctsComposite.Token)) + if(!await sendQueue.SendAsync(payload, ctsComposite.Token)) { // this will force a disconnect down the line throw new IOException($"Send queue stalled at {sendQueue.Count} of {SendQueueCapacity} items"); @@ -252,7 +252,7 @@ private async ValueTask SendAsync(T payload) private async Task FillReceivePipeAsync() { - while (true) + while(true) { logger.Debug(() => $"[{ConnectionId}] [NET] Waiting for data ..."); @@ -260,7 +260,7 @@ private async Task FillReceivePipeAsync() // read from network directly into pipe memory var cb = await networkStream.ReadAsync(memory, cts.Token); - if (cb == 0) + if(cb == 0) break; // EOF logger.Debug(() => $"[{ConnectionId}] [NET] Received data: {StratumConstants.Encoding.GetString(memory.ToArray(), 0, cb)}"); @@ -271,7 +271,7 @@ private async Task FillReceivePipeAsync() receivePipe.Writer.Advance(cb); var result = await receivePipe.Writer.FlushAsync(cts.Token); - if (result.IsCompleted) + if(result.IsCompleted) break; } } @@ -279,16 +279,16 @@ private async Task FillReceivePipeAsync() private async Task ProcessReceivePipeAsync(TcpProxyProtocolConfig proxyProtocol, Func onRequestAsync) { - while (true) + while(true) { logger.Debug(() => $"[{ConnectionId}] [PIPE] Waiting for data ..."); var result = await receivePipe.Reader.ReadAsync(cts.Token); - + var buffer = result.Buffer; SequencePosition? position = null; - if (buffer.Length > MaxInboundRequestLength) + if(buffer.Length > MaxInboundRequestLength) throw new InvalidDataException($"Incoming data exceeds maximum of {MaxInboundRequestLength}"); logger.Debug(() => $"[{ConnectionId}] [PIPE] Received data: {result.Buffer.AsString(StratumConstants.Encoding)}"); @@ -296,30 +296,30 @@ private async Task ProcessReceivePipeAsync(TcpProxyProtocolConfig proxyProtocol, do { // Scan buffer for line terminator - position = buffer.PositionOf((byte)'\n'); + position = buffer.PositionOf((byte) '\n'); - if (position != null) + if(position != null) { var slice = buffer.Slice(0, position.Value); - if (!expectingProxyHeader || !ProcessProxyHeader(slice, proxyProtocol)) + if(!expectingProxyHeader || !ProcessProxyHeader(slice, proxyProtocol)) await ProcessRequestAsync(onRequestAsync, slice); // Skip consumed section buffer = buffer.Slice(buffer.GetPosition(1, position.Value)); } - } while (position != null); + } while(position != null); receivePipe.Reader.AdvanceTo(buffer.Start, buffer.End); - if (result.IsCompleted) + if(result.IsCompleted) break; } } private async Task ProcessSendQueueAsync() { - while (true) + while(true) { var msg = await sendQueue.ReceiveAsync(cts.Token); @@ -335,10 +335,10 @@ private async Task SendMessage(object msg) try { - using (var stream = new MemoryStream(buffer, true)) + using(var stream = new MemoryStream(buffer, true)) { // serialize - using (var writer = new StreamWriter(stream, StratumConstants.Encoding, MaxOutboundRequestLength, true)) + using(var writer = new StreamWriter(stream, StratumConstants.Encoding, MaxOutboundRequestLength, true)) { serializer.Serialize(writer, msg); } @@ -346,9 +346,9 @@ private async Task SendMessage(object msg) stream.WriteByte((byte) '\n'); // terminator // send - using (var ctsTimeout = new CancellationTokenSource()) + using(var ctsTimeout = new CancellationTokenSource()) { - using (var ctsComposite = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, ctsTimeout.Token)) + using(var ctsComposite = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, ctsTimeout.Token)) { ctsTimeout.CancelAfter(sendTimeout); @@ -369,11 +369,11 @@ private async Task ProcessRequestAsync( Func onRequestAsync, ReadOnlySequence lineBuffer) { - using (var reader = new JsonTextReader(new StreamReader(new MemoryStream(lineBuffer.ToArray()), StratumConstants.Encoding))) + using(var reader = new JsonTextReader(new StreamReader(new MemoryStream(lineBuffer.ToArray()), StratumConstants.Encoding))) { var request = serializer.Deserialize(reader); - if (request == null) + if(request == null) throw new JsonException("Unable to deserialize request"); // Dispatch @@ -391,13 +391,13 @@ private bool ProcessProxyHeader(ReadOnlySequence seq, TcpProxyProtocolConf var line = seq.AsString(StratumConstants.Encoding); var peerAddress = RemoteEndpoint.Address; - if (line.StartsWith("PROXY ")) + if(line.StartsWith("PROXY ")) { var proxyAddresses = proxyProtocol.ProxyAddresses?.Select(x => IPAddress.Parse(x)).ToArray(); - if (proxyAddresses == null || !proxyAddresses.Any()) + if(proxyAddresses == null || !proxyAddresses.Any()) proxyAddresses = new[] { IPAddress.Loopback, IPUtils.IPv4LoopBackOnIPv6, IPAddress.IPv6Loopback }; - if (proxyAddresses.Any(x => x.Equals(peerAddress))) + if(proxyAddresses.Any(x => x.Equals(peerAddress))) { logger.Debug(() => $"[{ConnectionId}] Received Proxy-Protocol header: {line}"); @@ -419,7 +419,7 @@ private bool ProcessProxyHeader(ReadOnlySequence seq, TcpProxyProtocolConf return true; } - else if (proxyProtocol.Mandatory) + else if(proxyProtocol.Mandatory) { throw new InvalidDataException($"[{ConnectionId}] Missing mandatory Proxy-Protocol header from {peerAddress}. Closing connection."); } diff --git a/src/Miningcore/Stratum/StratumServer.cs b/src/Miningcore/Stratum/StratumServer.cs index dc12035b6..d02261eb8 100644 --- a/src/Miningcore/Stratum/StratumServer.cs +++ b/src/Miningcore/Stratum/StratumServer.cs @@ -59,7 +59,7 @@ protected StratumServer(IComponentContext ctx, IMasterClock clock) static StratumServer() { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { ignoredSocketErrors = new HashSet { @@ -69,7 +69,7 @@ static StratumServer() }; } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + else if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { // see: http://www.virtsync.com/c-error-codes-include-errno ignoredSocketErrors = new HashSet @@ -86,7 +86,7 @@ static StratumServer() protected readonly Dictionary clients = new Dictionary(); protected static readonly ConcurrentDictionary certs = new ConcurrentDictionary(); protected static readonly HashSet ignoredSocketErrors; - protected static readonly MethodBase StreamWriterCtor = typeof(StreamWriter).GetConstructor(new []{ typeof(Stream), typeof(Encoding), typeof(int), typeof(bool) }); + protected static readonly MethodBase StreamWriterCtor = typeof(StreamWriter).GetConstructor(new[] { typeof(Stream), typeof(Encoding), typeof(int), typeof(bool) }); protected readonly IComponentContext ctx; protected readonly IMasterClock clock; @@ -110,7 +110,7 @@ public void StartListeners(params (IPEndPoint IPEndPoint, PoolEndpoint PoolEndpo server.Bind(port.IPEndPoint); server.Listen(512); - lock (ports) + lock(ports) { ports[port.IPEndPoint.Port] = server; } @@ -123,7 +123,7 @@ public void StartListeners(params (IPEndPoint IPEndPoint, PoolEndpoint PoolEndpo // Setup accept tasks var tasks = sockets.Select(socket => socket.AcceptAsync()).ToArray(); - while (true) + while(true) { try { @@ -137,11 +137,11 @@ public void StartListeners(params (IPEndPoint IPEndPoint, PoolEndpoint PoolEndpo var port = stratumPorts[i]; // skip running tasks - if (!(task.IsCompleted || task.IsFaulted || task.IsCanceled)) + if(!(task.IsCompleted || task.IsFaulted || task.IsCanceled)) continue; // accept connection if successful - if (task.IsCompletedSuccessfully) + if(task.IsCompletedSuccessfully) AcceptConnection(task.Result, port); // Refresh task @@ -169,7 +169,7 @@ private void AcceptConnection(Socket socket, (IPEndPoint IPEndPoint, PoolEndpoin var connectionId = CorrelationIdGenerator.GetNextId(); // get rid of banned clients as early as possible - if (banManager?.IsBanned(remoteEndpoint.Address) == true) + if(banManager?.IsBanned(remoteEndpoint.Address) == true) { logger.Debug(() => $"Disconnecting banned ip {remoteEndpoint.Address}"); socket.Close(); @@ -179,9 +179,9 @@ private void AcceptConnection(Socket socket, (IPEndPoint IPEndPoint, PoolEndpoin // TLS cert loading X509Certificate2 cert = null; - if (port.PoolEndpoint.Tls) + if(port.PoolEndpoint.Tls) { - if (!certs.TryGetValue(port.PoolEndpoint.TlsPfxFile, out cert)) + if(!certs.TryGetValue(port.PoolEndpoint.TlsPfxFile, out cert)) cert = AddCert(port); } @@ -212,7 +212,7 @@ protected virtual void RegisterClient(StratumClient client, string connectionId) { Contract.RequiresNonNull(client, nameof(client)); - lock (clients) + lock(clients) { clients[connectionId] = client; } @@ -224,9 +224,9 @@ protected virtual void UnregisterClient(StratumClient client) var subscriptionId = client.ConnectionId; - if (!string.IsNullOrEmpty(subscriptionId)) + if(!string.IsNullOrEmpty(subscriptionId)) { - lock (clients) + lock(clients) { clients.Remove(subscriptionId); } @@ -238,7 +238,7 @@ protected virtual void UnregisterClient(StratumClient client) protected async Task OnRequestAsync(StratumClient client, JsonRpcRequest request, CancellationToken ct) { // boot pre-connected clients - if (banManager?.IsBanned(client.RemoteEndpoint.Address) == true) + if(banManager?.IsBanned(client.RemoteEndpoint.Address) == true) { logger.Info(() => $"[{client.ConnectionId}] Disconnecting banned client @ {client.RemoteEndpoint.Address}"); DisconnectClient(client); @@ -252,16 +252,16 @@ protected async Task OnRequestAsync(StratumClient client, JsonRpcRequest request protected virtual void OnClientError(StratumClient client, Exception ex) { - if (ex is AggregateException) + if(ex is AggregateException) ex = ex.InnerException; - if (ex is IOException && ex.InnerException != null) + if(ex is IOException && ex.InnerException != null) ex = ex.InnerException; - switch (ex) + switch(ex) { case SocketException sockEx: - if (!ignoredSocketErrors.Contains(sockEx.ErrorCode)) + if(!ignoredSocketErrors.Contains(sockEx.ErrorCode)) logger.Error(() => $"[{client.ConnectionId}] Connection error state: {ex}"); break; @@ -269,18 +269,18 @@ protected virtual void OnClientError(StratumClient client, Exception ex) // junk received (invalid json) logger.Error(() => $"[{client.ConnectionId}] Connection json error state: {jsonEx.Message}"); - if (clusterConfig.Banning?.BanOnJunkReceive.HasValue == false || clusterConfig.Banning?.BanOnJunkReceive == true) + if(clusterConfig.Banning?.BanOnJunkReceive.HasValue == false || clusterConfig.Banning?.BanOnJunkReceive == true) { logger.Info(() => $"[{client.ConnectionId}] Banning client for sending junk"); banManager?.Ban(client.RemoteEndpoint.Address, TimeSpan.FromMinutes(3)); } break; - + case AuthenticationException authEx: // junk received (SSL handshake) logger.Error(() => $"[{client.ConnectionId}] Connection json error state: {authEx.Message}"); - if (clusterConfig.Banning?.BanOnJunkReceive.HasValue == false || clusterConfig.Banning?.BanOnJunkReceive == true) + if(clusterConfig.Banning?.BanOnJunkReceive.HasValue == false || clusterConfig.Banning?.BanOnJunkReceive == true) { logger.Info(() => $"[{client.ConnectionId}] Banning client for failing SSL handshake"); banManager?.Ban(client.RemoteEndpoint.Address, TimeSpan.FromMinutes(3)); @@ -291,9 +291,9 @@ protected virtual void OnClientError(StratumClient client, Exception ex) // junk received (SSL handshake) logger.Error(() => $"[{client.ConnectionId}] Connection json error state: {ioEx.Message}"); - if (ioEx.Source == "System.Net.Security") + if(ioEx.Source == "System.Net.Security") { - if (clusterConfig.Banning?.BanOnJunkReceive.HasValue == false || clusterConfig.Banning?.BanOnJunkReceive == true) + if(clusterConfig.Banning?.BanOnJunkReceive.HasValue == false || clusterConfig.Banning?.BanOnJunkReceive == true) { logger.Info(() => $"[{client.ConnectionId}] Banning client for failing SSL handshake"); banManager?.Ban(client.RemoteEndpoint.Address, TimeSpan.FromMinutes(3)); @@ -346,7 +346,7 @@ private X509Certificate2 AddCert((IPEndPoint IPEndPoint, PoolEndpoint PoolEndpoi return tlsCert; } - catch (Exception ex) + catch(Exception ex) { logger.Info(() => $"Failed to load TLS certificate {port.PoolEndpoint.TlsPfxFile}: {ex.Message}"); throw; @@ -380,7 +380,7 @@ protected IEnumerable ForEachClient(Func func) { StratumClient[] tmp; - lock (clients) + lock(clients) { tmp = clients.Values.ToArray(); } diff --git a/src/Miningcore/Util/BigRational.cs b/src/Miningcore/Util/BigRational.cs index b38df5b44..913a53e98 100644 --- a/src/Miningcore/Util/BigRational.cs +++ b/src/Miningcore/Util/BigRational.cs @@ -155,10 +155,10 @@ public BigRational GetFractionPart() public override bool Equals(object obj) { - if (obj == null) + if(obj == null) return false; - if (!(obj is BigRational)) + if(!(obj is BigRational)) return false; return Equals((BigRational) obj); } @@ -171,9 +171,9 @@ public override int GetHashCode() // IComparable int IComparable.CompareTo(object obj) { - if (obj == null) + if(obj == null) return 1; - if (!(obj is BigRational)) + if(!(obj is BigRational)) throw new ArgumentException("Argument must be of type BigRational", "obj"); return Compare(this, (BigRational) obj); } @@ -198,7 +198,7 @@ public override string ToString() // a/b = c/d, iff ad = bc public bool Equals(BigRational other) { - if (Denominator == other.Denominator) + if(Denominator == other.Denominator) return m_numerator == other.m_numerator; return m_numerator * other.Denominator == Denominator * other.m_numerator; } @@ -218,14 +218,14 @@ public BigRational(BigInteger numerator) // BigRational(Double) public BigRational(double value) { - if (double.IsNaN(value)) + if(double.IsNaN(value)) throw new ArgumentException("Argument is not a number", nameof(value)); - if (double.IsInfinity(value)) + if(double.IsInfinity(value)) throw new ArgumentException("Argument is infinity", nameof(value)); SplitDoubleIntoParts(value, out var sign, out var exponent, out var significand, out _); - if (significand == 0) + if(significand == 0) { this = Zero; return; @@ -234,11 +234,11 @@ public BigRational(double value) m_numerator = significand; Denominator = 1 << 52; - if (exponent > 0) + if(exponent > 0) m_numerator = BigInteger.Pow(m_numerator, exponent); - else if (exponent < 0) + else if(exponent < 0) Denominator = BigInteger.Pow(Denominator, -exponent); - if (sign < 0) + if(sign < 0) m_numerator = BigInteger.Negate(m_numerator); Simplify(); } @@ -251,11 +251,11 @@ public BigRational(double value) public BigRational(decimal value) { var bits = decimal.GetBits(value); - if (bits == null || bits.Length != 4 || (bits[3] & ~(DecimalSignMask | DecimalScaleMask)) != 0 || + if(bits == null || bits.Length != 4 || (bits[3] & ~(DecimalSignMask | DecimalScaleMask)) != 0 || (bits[3] & DecimalScaleMask) > 28 << 16) throw new ArgumentException("invalid Decimal", nameof(value)); - if (value == decimal.Zero) + if(value == decimal.Zero) { this = Zero; return; @@ -266,7 +266,7 @@ public BigRational(decimal value) m_numerator = (new BigInteger(ul) << 32) | (uint) bits[0]; // (hiMid << 32) | (low) var isNegative = (bits[3] & DecimalSignMask) != 0; - if (isNegative) + if(isNegative) m_numerator = BigInteger.Negate(m_numerator); // build up the denominator @@ -278,15 +278,15 @@ public BigRational(decimal value) public BigRational(BigInteger numerator, BigInteger denominator) { - if (denominator.Sign == 0) + if(denominator.Sign == 0) throw new DivideByZeroException(); - if (numerator.Sign == 0) + if(numerator.Sign == 0) { // 0/m -> 0/1 m_numerator = BigInteger.Zero; Denominator = BigInteger.One; } - else if (denominator.Sign < 0) + else if(denominator.Sign < 0) { m_numerator = BigInteger.Negate(numerator); Denominator = BigInteger.Negate(denominator); @@ -302,14 +302,14 @@ public BigRational(BigInteger numerator, BigInteger denominator) public BigRational(BigInteger whole, BigInteger numerator, BigInteger denominator) { - if (denominator.Sign == 0) + if(denominator.Sign == 0) throw new DivideByZeroException(); - if (numerator.Sign == 0 && whole.Sign == 0) + if(numerator.Sign == 0 && whole.Sign == 0) { m_numerator = BigInteger.Zero; Denominator = BigInteger.One; } - else if (denominator.Sign < 0) + else if(denominator.Sign < 0) { Denominator = BigInteger.Negate(denominator); m_numerator = BigInteger.Negate(whole) * Denominator + BigInteger.Negate(numerator); @@ -385,11 +385,11 @@ public static BigRational DivRem(BigRational dividend, BigRational divisor, out public static BigRational Pow(BigRational baseValue, BigInteger exponent) { - if (exponent.Sign == 0) + if(exponent.Sign == 0) return One; - if (exponent.Sign < 0) + if(exponent.Sign < 0) { - if (baseValue == Zero) + if(baseValue == Zero) throw new ArgumentException("cannot raise zero to a negative power", nameof(baseValue)); // n^(-e) -> (1/n)^e baseValue = Invert(baseValue); @@ -584,12 +584,12 @@ public static explicit operator double(BigRational value) // The Double value type represents a double-precision 64-bit number with // values ranging from -1.79769313486232e308 to +1.79769313486232e308 // values that do not fit into this range are returned as +/-Infinity - if (SafeCastToDouble(value.m_numerator) && SafeCastToDouble(value.Denominator)) + if(SafeCastToDouble(value.m_numerator) && SafeCastToDouble(value.Denominator)) return (double) value.m_numerator / (double) value.Denominator; // scale the numerator to preseve the fraction part through the integer division var denormalized = value.m_numerator * s_bnDoublePrecision / value.Denominator; - if (denormalized.IsZero) + if(denormalized.IsZero) return value.Sign < 0 ? BitConverter.Int64BitsToDouble(unchecked((long) 0x8000000000000000)) : 0d; // underflow to -+0 @@ -600,8 +600,8 @@ public static explicit operator double(BigRational value) while(scale > 0) { - if (!isDouble) - if (SafeCastToDouble(denormalized)) + if(!isDouble) + if(SafeCastToDouble(denormalized)) { result = (double) denormalized; isDouble = true; @@ -615,7 +615,7 @@ public static explicit operator double(BigRational value) scale--; } - if (!isDouble) + if(!isDouble) return value.Sign < 0 ? double.NegativeInfinity : double.PositiveInfinity; return result; } @@ -625,15 +625,15 @@ public static explicit operator decimal(BigRational value) // The Decimal value type represents decimal numbers ranging // from +79,228,162,514,264,337,593,543,950,335 to -79,228,162,514,264,337,593,543,950,335 // the binary representation of a Decimal value is of the form, ((-2^96 to 2^96) / 10^(0 to 28)) - if (SafeCastToDecimal(value.m_numerator) && SafeCastToDecimal(value.Denominator)) + if(SafeCastToDecimal(value.m_numerator) && SafeCastToDecimal(value.Denominator)) return (decimal) value.m_numerator / (decimal) value.Denominator; // scale the numerator to preseve the fraction part through the integer division var denormalized = value.m_numerator * s_bnDecimalPrecision / value.Denominator; - if (denormalized.IsZero) + if(denormalized.IsZero) return decimal.Zero; // underflow - fraction is too small to fit in a decimal for(var scale = DecimalMaxScale; scale >= 0; scale--) - if (!SafeCastToDecimal(denormalized)) + if(!SafeCastToDecimal(denormalized)) { denormalized = denormalized / 10; } @@ -729,14 +729,14 @@ void IDeserializationCallback.OnDeserialization(object sender) try { // verify that the deserialized number is well formed - if (Denominator.Sign == 0 || m_numerator.Sign == 0) + if(Denominator.Sign == 0 || m_numerator.Sign == 0) { // n/0 -> 0/1 // 0/m -> 0/1 m_numerator = BigInteger.Zero; Denominator = BigInteger.One; } - else if (Denominator.Sign < 0) + else if(Denominator.Sign < 0) { m_numerator = BigInteger.Negate(m_numerator); Denominator = BigInteger.Negate(Denominator); @@ -753,7 +753,7 @@ void IDeserializationCallback.OnDeserialization(object sender) [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)] void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { - if (info == null) + if(info == null) throw new ArgumentNullException(nameof(info)); info.AddValue("Numerator", m_numerator); @@ -762,7 +762,7 @@ void ISerializable.GetObjectData(SerializationInfo info, StreamingContext contex private BigRational(SerializationInfo info, StreamingContext context) { - if (info == null) + if(info == null) throw new ArgumentNullException(nameof(info)); m_numerator = (BigInteger) info.GetValue("Numerator", typeof(BigInteger)); @@ -779,11 +779,11 @@ private void Simplify() { // * if the numerator is {0, +1, -1} then the fraction is already reduced // * if the denominator is {+1} then the fraction is already reduced - if (m_numerator == BigInteger.Zero) + if(m_numerator == BigInteger.Zero) Denominator = BigInteger.One; var gcd = BigInteger.GreatestCommonDivisor(m_numerator, Denominator); - if (gcd > BigInteger.One) + if(gcd > BigInteger.One) { m_numerator = m_numerator / gcd; Denominator = Denominator / gcd; @@ -816,14 +816,14 @@ private static void SplitDoubleIntoParts(double dbl, out int sign, out int exp, sign = 1 - ((int) (du.uu >> 62) & 2); man = du.uu & 0x000FFFFFFFFFFFFF; exp = (int) (du.uu >> 52) & 0x7FF; - if (exp == 0) + if(exp == 0) { // Denormalized number. isFinite = true; - if (man != 0) + if(man != 0) exp = -1074; } - else if (exp == 0x7FF) + else if(exp == 0x7FF) { // NaN or Infinite. isFinite = false; @@ -842,7 +842,7 @@ private static double GetDoubleFromParts(int sign, int exp, ulong man) DoubleUlong du; du.dbl = 0; - if (man == 0) + if(man == 0) { du.uu = 0; } @@ -850,7 +850,7 @@ private static double GetDoubleFromParts(int sign, int exp, ulong man) { // Normalize so that 0x0010 0000 0000 0000 is the highest bit set var cbitShift = CbitHighZero(man) - 11; - if (cbitShift < 0) + if(cbitShift < 0) man >>= -cbitShift; else man <<= cbitShift; @@ -859,16 +859,16 @@ private static double GetDoubleFromParts(int sign, int exp, ulong man) // (52 bits) and skew the exponent (by 0x3FF == 1023) exp += 1075; - if (exp >= 0x7FF) + if(exp >= 0x7FF) { // Infinity du.uu = 0x7FF0000000000000; } - else if (exp <= 0) + else if(exp <= 0) { // Denormalized exp--; - if (exp < -52) + if(exp < -52) du.uu = 0; else du.uu = man >> -exp; @@ -880,7 +880,7 @@ private static double GetDoubleFromParts(int sign, int exp, ulong man) } } - if (sign < 0) + if(sign < 0) du.uu |= 0x8000000000000000; return du.dbl; @@ -888,42 +888,42 @@ private static double GetDoubleFromParts(int sign, int exp, ulong man) private static int CbitHighZero(ulong uu) { - if ((uu & 0xFFFFFFFF00000000) == 0) + if((uu & 0xFFFFFFFF00000000) == 0) return 32 + CbitHighZero((uint) uu); return CbitHighZero((uint) (uu >> 32)); } private static int CbitHighZero(uint u) { - if (u == 0) + if(u == 0) return 32; var cbit = 0; - if ((u & 0xFFFF0000) == 0) + if((u & 0xFFFF0000) == 0) { cbit += 16; u <<= 16; } - if ((u & 0xFF000000) == 0) + if((u & 0xFF000000) == 0) { cbit += 8; u <<= 8; } - if ((u & 0xF0000000) == 0) + if((u & 0xF0000000) == 0) { cbit += 4; u <<= 4; } - if ((u & 0xC0000000) == 0) + if((u & 0xC0000000) == 0) { cbit += 2; u <<= 2; } - if ((u & 0x80000000) == 0) + if((u & 0x80000000) == 0) cbit += 1; return cbit; } diff --git a/src/Miningcore/Util/CircularBuffer.cs b/src/Miningcore/Util/CircularBuffer.cs index a5e31dad1..1cd69f164 100644 --- a/src/Miningcore/Util/CircularBuffer.cs +++ b/src/Miningcore/Util/CircularBuffer.cs @@ -61,12 +61,12 @@ public CircularBuffer(int capacity) /// public CircularBuffer(int capacity, T[] items) { - if (capacity < 1) + if(capacity < 1) throw new ArgumentException( "Circular buffer cannot have negative or zero capacity.", nameof(capacity)); - if (items == null) + if(items == null) throw new ArgumentNullException(nameof(items)); - if (items.Length > capacity) + if(items.Length > capacity) throw new ArgumentException( "Too many items to fit circular buffer", nameof(items)); @@ -115,10 +115,10 @@ public T this[int index] { get { - if (IsEmpty) + if(IsEmpty) throw new IndexOutOfRangeException( string.Format("Cannot access index {0}. Buffer is empty", index)); - if (index >= size) + if(index >= size) throw new IndexOutOfRangeException( string.Format("Cannot access index {0}. Buffer size is {1}", index, size)); var actualIndex = InternalIndex(index); @@ -126,10 +126,10 @@ public T this[int index] } set { - if (IsEmpty) + if(IsEmpty) throw new IndexOutOfRangeException( string.Format("Cannot access index {0}. Buffer is empty", index)); - if (index >= size) + if(index >= size) throw new IndexOutOfRangeException( string.Format("Cannot access index {0}. Buffer size is {1}", index, size)); var actualIndex = InternalIndex(index); @@ -187,7 +187,7 @@ public T Back() /// Item to push to the back of the buffer public void PushBack(T item) { - if (IsFull) + if(IsFull) { buffer[end] = item; Increment(ref end); @@ -210,7 +210,7 @@ public void PushBack(T item) /// Item to push to the front of the buffer public void PushFront(T item) { - if (IsFull) + if(IsFull) { Decrement(ref start); end = start; @@ -270,7 +270,7 @@ public T[] ToArray() private void ThrowIfEmpty(string message = "Cannot access an empty buffer.") { - if (IsEmpty) + if(IsEmpty) throw new InvalidOperationException(message); } @@ -281,7 +281,7 @@ private void ThrowIfEmpty(string message = "Cannot access an empty buffer.") /// private void Increment(ref int index) { - if (++index == Capacity) + if(++index == Capacity) index = 0; } @@ -292,7 +292,7 @@ private void Increment(ref int index) /// private void Decrement(ref int index) { - if (index == 0) + if(index == 0) index = Capacity; index--; } @@ -323,14 +323,14 @@ private int InternalIndex(int index) private ArraySegment ArrayOne() { - if (start < end) + if(start < end) return new ArraySegment(buffer, start, end - start); return new ArraySegment(buffer, start, buffer.Length - start); } private ArraySegment ArrayTwo() { - if (start < end) + if(start < end) return new ArraySegment(buffer, end, 0); return new ArraySegment(buffer, 0, end); } diff --git a/src/Miningcore/Util/ScheduledSubject.cs b/src/Miningcore/Util/ScheduledSubject.cs index efd98ec2e..b604ec9e1 100644 --- a/src/Miningcore/Util/ScheduledSubject.cs +++ b/src/Miningcore/Util/ScheduledSubject.cs @@ -15,7 +15,7 @@ public ScheduledSubject(IScheduler scheduler, IObserver defaultObserver = nul _defaultObserver = defaultObserver; _subject = defaultSubject ?? new Subject(); - if (defaultObserver != null) + if(defaultObserver != null) _defaultObserverSub = _subject.ObserveOn(_scheduler).Subscribe(_defaultObserver); } @@ -51,14 +51,14 @@ public IDisposable Subscribe(IObserver observer) _subject.ObserveOn(_scheduler).Subscribe(observer), Disposable.Create(() => { - if (Interlocked.Decrement(ref _observerRefCount) <= 0 && _defaultObserver != null) + if(Interlocked.Decrement(ref _observerRefCount) <= 0 && _defaultObserver != null) _defaultObserverSub = _subject.ObserveOn(_scheduler).Subscribe(_defaultObserver); })); } public void Dispose() { - if (_subject is IDisposable) + if(_subject is IDisposable) ((IDisposable) _subject).Dispose(); } } diff --git a/src/Miningcore/VarDiff/VarDiffManager.cs b/src/Miningcore/VarDiff/VarDiffManager.cs index 0bba5c0ef..e4d776e9f 100644 --- a/src/Miningcore/VarDiff/VarDiffManager.cs +++ b/src/Miningcore/VarDiff/VarDiffManager.cs @@ -55,7 +55,7 @@ public VarDiffManager(VarDiffConfig varDiffOptions, IMasterClock clock) var ts = DateTimeOffset.Now.ToUnixTimeMilliseconds() / 1000.0; // For the first time, won't change diff. - if (!ctx.LastTs.HasValue) + if(!ctx.LastTs.HasValue) { ctx.LastRtc = ts; ctx.LastTs = ts; @@ -73,41 +73,41 @@ public VarDiffManager(VarDiffConfig varDiffOptions, IMasterClock clock) var avg = (timeTotal + sinceLast) / (timeCount + 1); // Once there is a share submitted, store the time into the buffer and update the last time. - if (!isIdleUpdate) + if(!isIdleUpdate) { ctx.TimeBuffer.PushBack(sinceLast); ctx.LastTs = ts; } // Check if we need to change the difficulty - if (ts - ctx.LastRtc < options.RetargetTime || avg >= tMin && avg <= tMax) + if(ts - ctx.LastRtc < options.RetargetTime || avg >= tMin && avg <= tMax) return null; // Possible New Diff var newDiff = difficulty * options.TargetTime / avg; // Max delta - if (options.MaxDelta.HasValue && options.MaxDelta > 0) + if(options.MaxDelta.HasValue && options.MaxDelta > 0) { var delta = Math.Abs(newDiff - difficulty); - if (delta > options.MaxDelta) + if(delta > options.MaxDelta) { - if (newDiff > difficulty) + if(newDiff > difficulty) newDiff -= delta - options.MaxDelta.Value; - else if (newDiff < difficulty) + else if(newDiff < difficulty) newDiff += delta - options.MaxDelta.Value; } } // Clamp to valid range - if (newDiff < minDiff) + if(newDiff < minDiff) newDiff = minDiff; - if (newDiff > maxDiff) + if(newDiff > maxDiff) newDiff = maxDiff; // RTC if the Diff is changed - if (newDiff < difficulty || newDiff > difficulty) + if(newDiff < difficulty || newDiff > difficulty) { ctx.LastRtc = ts; ctx.LastUpdate = clock.Now; From a7c55596d3bd3ebb3fcb0c63bd25b90ef0d42862 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Thu, 4 Apr 2019 13:45:34 +0200 Subject: [PATCH 121/178] Relocate .editorconfig again --- src/{Miningcore => }/.editorconfig | 0 .../Blockchain/Bitcoin/BitcoinJobTests.cs | 24 ++-- .../Cryptonote/CryptonoteJobTests.cs | 22 ++-- .../Blockchain/Ethereum/EthereumJobTests.cs | 12 +- src/Miningcore.Tests/Crypto/CrytonoteTests.cs | 4 +- src/Miningcore.Tests/Crypto/HashingTests.cs | 2 +- .../Crypto/MerkleTreeTests.cs | 6 +- src/Miningcore.Tests/ModuleInitializer.cs | 4 +- .../VarDiff/VarDiffManagerTests.cs | 106 +++++++++--------- 9 files changed, 90 insertions(+), 90 deletions(-) rename src/{Miningcore => }/.editorconfig (100%) diff --git a/src/Miningcore/.editorconfig b/src/.editorconfig similarity index 100% rename from src/Miningcore/.editorconfig rename to src/.editorconfig diff --git a/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs b/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs index 1e378da14..bcdd1f21b 100644 --- a/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs +++ b/src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs @@ -34,13 +34,13 @@ public BitcoinJobTests() [Fact] public void BitcoinJob_Should_Accept_Valid_Share() { - var worker = new StratumClient(); + var worker = new StratumClient(); - worker.SetContext(new BitcoinWorkerContext - { - Difficulty = 0.5, - ExtraNonce1 = "01000058", - }); + worker.SetContext(new BitcoinWorkerContext + { + Difficulty = 0.5, + ExtraNonce1 = "01000058", + }); var bt = JsonConvert.DeserializeObject( "{\"Version\":536870912,\"PreviousBlockhash\":\"000000000909578519b5be7b37fdc53b2923817921c43108a907b72264da76bb\",\"CoinbaseValue\":5000000000,\"Target\":\"7fffff0000000000000000000000000000000000000000000000000000000000\",\"NonceRange\":\"00000000ffffffff\",\"CurTime\":1508869874,\"Bits\":\"207fffff\",\"Height\":14,\"Transactions\":[],\"CoinbaseAux\":{\"Flags\":\"0b2f454231362f414431322f\"},\"default_witness_commitment\":null}"); @@ -69,13 +69,13 @@ public void BitcoinJob_Should_Accept_Valid_Share() [Fact] public void BitcoinJob_Should_Not_Accept_Invalid_Share() { - var worker = new StratumClient(); + var worker = new StratumClient(); - worker.SetContext(new BitcoinWorkerContext - { - Difficulty = 0.5, - ExtraNonce1 = "01000058", - }); + worker.SetContext(new BitcoinWorkerContext + { + Difficulty = 0.5, + ExtraNonce1 = "01000058", + }); var bt = JsonConvert.DeserializeObject( "{\"Version\":536870912,\"PreviousBlockhash\":\"000000000909578519b5be7b37fdc53b2923817921c43108a907b72264da76bb\",\"CoinbaseValue\":5000000000,\"Target\":\"7fffff0000000000000000000000000000000000000000000000000000000000\",\"NonceRange\":\"00000000ffffffff\",\"CurTime\":1508869874,\"Bits\":\"207fffff\",\"Height\":14,\"Transactions\":[],\"CoinbaseAux\":{\"Flags\":\"0b2f454231362f414431322f\"},\"default_witness_commitment\":null}"); diff --git a/src/Miningcore.Tests/Blockchain/Cryptonote/CryptonoteJobTests.cs b/src/Miningcore.Tests/Blockchain/Cryptonote/CryptonoteJobTests.cs index 6b5226977..200120e28 100644 --- a/src/Miningcore.Tests/Blockchain/Cryptonote/CryptonoteJobTests.cs +++ b/src/Miningcore.Tests/Blockchain/Cryptonote/CryptonoteJobTests.cs @@ -47,12 +47,12 @@ public void MoneroJob_PrepareWorkerJob() [Fact] public void MoneroJob_Should_Accept_Valid_Share() { - var worker = new StratumClient(); + var worker = new StratumClient(); - worker.SetContext(new CryptonoteWorkerContext - { - Difficulty = 1000, - }); + worker.SetContext(new CryptonoteWorkerContext + { + Difficulty = 1000, + }); var bt = JsonConvert.DeserializeObject( "{\"blocktemplate_blob\":\"0106e7eabdcf058234351e2e6ea901a56b33bb531587424321873072d80a9e97295b6c43152b9d00000000019c0201ffe00106e3a1a0cc010275d92c0a057aa5f073079694a153d426f837f49fdb9654da10a5364e79a2086280a0d9e61d028b46dca0d04998500b40b046fd6f8bb33229e6380fd465dbb1327aa6f813d8bd80c0fc82aa0202372f076459e769116d604d30aabff7160782acc0d20e0c5cdc8963ed4e16372f8090cad2c60e02f009504ce65538bbb684b466b21be3a90e3740f185d7089d37b75f0cf62b6e7680e08d84ddcb0102cf01b85c0b592bb6e508e20b5d317052b75de121908390363201abff3476ef0180c0caf384a302024b81076c8ad0cfe84cc32fe0813d63cdd0f7d8d0e56d82aa3f58cbbe49d4c61e2b017aaf3074be7ecb30a769595758e4da7c7c87ead864baf89b679b73153dfa352c0208000000000000000000\",\"Difficulty\":2,\"Height\":224,\"prev_hash\":\"8234351e2e6ea901a56b33bb531587424321873072d80a9e97295b6c43152b9d\",\"reserved_offset\":322,\"Status\":\"OK\"}"); @@ -71,14 +71,14 @@ public void MoneroJob_Should_Accept_Valid_Share() [Fact] public void MoneroJob_Should_Not_Accept_Invalid_Share() { - var worker = new StratumClient(); + var worker = new StratumClient(); - worker.SetContext(new CryptonoteWorkerContext - { - Difficulty = 1000, - }); + worker.SetContext(new CryptonoteWorkerContext + { + Difficulty = 1000, + }); - var bt = JsonConvert.DeserializeObject( + var bt = JsonConvert.DeserializeObject( "{\"blocktemplate_blob\":\"0106e7eabdcf058234351e2e6ea901a56b33bb531587424321873072d80a9e97295b6c43152b9d00000000019c0201ffe00106e3a1a0cc010275d92c0a057aa5f073079694a153d426f837f49fdb9654da10a5364e79a2086280a0d9e61d028b46dca0d04998500b40b046fd6f8bb33229e6380fd465dbb1327aa6f813d8bd80c0fc82aa0202372f076459e769116d604d30aabff7160782acc0d20e0c5cdc8963ed4e16372f8090cad2c60e02f009504ce65538bbb684b466b21be3a90e3740f185d7089d37b75f0cf62b6e7680e08d84ddcb0102cf01b85c0b592bb6e508e20b5d317052b75de121908390363201abff3476ef0180c0caf384a302024b81076c8ad0cfe84cc32fe0813d63cdd0f7d8d0e56d82aa3f58cbbe49d4c61e2b017aaf3074be7ecb30a769595758e4da7c7c87ead864baf89b679b73153dfa352c0208000000000000000000\",\"Difficulty\":2,\"Height\":224,\"prev_hash\":\"8234351e2e6ea901a56b33bb531587424321873072d80a9e97295b6c43152b9d\",\"reserved_offset\":322,\"Status\":\"OK\"}"); var job = new CryptonoteJob(bt, "d150da".HexToByteArray(), "1", poolConfig, clusterConfig, ""); diff --git a/src/Miningcore.Tests/Blockchain/Ethereum/EthereumJobTests.cs b/src/Miningcore.Tests/Blockchain/Ethereum/EthereumJobTests.cs index 1392c206b..db03cb00a 100644 --- a/src/Miningcore.Tests/Blockchain/Ethereum/EthereumJobTests.cs +++ b/src/Miningcore.Tests/Blockchain/Ethereum/EthereumJobTests.cs @@ -8,15 +8,15 @@ namespace Miningcore.Tests.Blockchain.Ethereum { - /// - /// These tests take ages to complete (> 10 min. on modern hardware) - /// due to the time it takes to generate the DAG for EthashFull - /// - public class EthereumJobTests : TestBase + /// + /// These tests take ages to complete (> 10 min. on modern hardware) + /// due to the time it takes to generate the DAG for EthashFull + /// + public class EthereumJobTests : TestBase { static readonly EthashFull ethash = new EthashFull(3, Path.GetTempPath()); - /* + /* [Fact] public async Task EthereumJob_Should_Accept_Valid_Share() { diff --git a/src/Miningcore.Tests/Crypto/CrytonoteTests.cs b/src/Miningcore.Tests/Crypto/CrytonoteTests.cs index f7977a799..939738d3b 100644 --- a/src/Miningcore.Tests/Crypto/CrytonoteTests.cs +++ b/src/Miningcore.Tests/Crypto/CrytonoteTests.cs @@ -17,8 +17,8 @@ public void Crytonight() LibCryptonight.Cryptonight(blobConverted, buf, CryptonightVariant.VARIANT_0, 0); var result = buf.ToHexString(); Assert.Equal("a845ffbdf83ae9a8ffa504a1011efbd5ed2294bb9da591d3b583740568402c00", result); - - Array.Clear(buf,0, buf.Length); + + Array.Clear(buf, 0, buf.Length); LibCryptonight.Cryptonight(blobConverted, buf, CryptonightVariant.VARIANT_0, 0); result = buf.ToHexString(); diff --git a/src/Miningcore.Tests/Crypto/HashingTests.cs b/src/Miningcore.Tests/Crypto/HashingTests.cs index 4d3414dde..ffdd277ee 100644 --- a/src/Miningcore.Tests/Crypto/HashingTests.cs +++ b/src/Miningcore.Tests/Crypto/HashingTests.cs @@ -119,7 +119,7 @@ public void Lyra2Rev3_Hash() { var hasher = new Lyra2Rev3(); var hash = new byte[32]; - hasher.Digest(Enumerable.Repeat((byte)5, 80).ToArray(), hash); + hasher.Digest(Enumerable.Repeat((byte) 5, 80).ToArray(), hash); var result = hash.ToHexString(); Assert.Equal("c56ec425ada2c8ddcb8d5a79a3a0c9d79f66318193049fb81f875c537a4f963d", result); diff --git a/src/Miningcore.Tests/Crypto/MerkleTreeTests.cs b/src/Miningcore.Tests/Crypto/MerkleTreeTests.cs index 3328f7782..f6535c057 100644 --- a/src/Miningcore.Tests/Crypto/MerkleTreeTests.cs +++ b/src/Miningcore.Tests/Crypto/MerkleTreeTests.cs @@ -80,7 +80,7 @@ public void MerkleTree_99HashesTest_Branches() { List hashesList = new List(); - for (int i = 0; i < 100; i++) + for(int i = 0; i < 100; i++) { byte[] value = Encoding.ASCII.GetBytes(i.ToString()); byte[] hash = MerkelHash(value); @@ -94,7 +94,7 @@ public void MerkleTree_99HashesTest_Branches() .ToArray(); - foreach (var hex in output) + foreach(var hex in output) this.output.WriteLine(hex); string[] expectedOutput = { @@ -114,7 +114,7 @@ public void MerkleTree_99HashesTest_Branches() private static byte[] MerkelHash(byte[] input) { - using (var hash = SHA256.Create()) + using(var hash = SHA256.Create()) { var first = hash.ComputeHash(input, 0, input.Length); return hash.ComputeHash(first); diff --git a/src/Miningcore.Tests/ModuleInitializer.cs b/src/Miningcore.Tests/ModuleInitializer.cs index c47fc7c39..9bc89615d 100644 --- a/src/Miningcore.Tests/ModuleInitializer.cs +++ b/src/Miningcore.Tests/ModuleInitializer.cs @@ -25,9 +25,9 @@ public static class ModuleInitializer /// public static void Initialize() { - lock (initLock) + lock(initLock) { - if (isInitialized) + if(isInitialized) return; var builder = new ContainerBuilder(); diff --git a/src/Miningcore.Tests/VarDiff/VarDiffManagerTests.cs b/src/Miningcore.Tests/VarDiff/VarDiffManagerTests.cs index 938831ecf..b4d4dd353 100644 --- a/src/Miningcore.Tests/VarDiff/VarDiffManagerTests.cs +++ b/src/Miningcore.Tests/VarDiff/VarDiffManagerTests.cs @@ -12,67 +12,67 @@ namespace Miningcore.Tests.VarDiff { public class VarDiffManagerTests : TestBase { -/* - private static readonly VarDiffConfig config = new VarDiffConfig - { - RetargetTime = 90, - MinDiff = 1000, - MaxDiff = 10000, - TargetTime = 15, - VariancePercent = 30, - MaxDelta = 1000, - }; + /* + private static readonly VarDiffConfig config = new VarDiffConfig + { + RetargetTime = 90, + MinDiff = 1000, + MaxDiff = 10000, + TargetTime = 15, + VariancePercent = 30, + MaxDelta = 1000, + }; - private static readonly ILogger logger = LogManager.CreateNullLogger(); - private readonly MockMasterClock clock = new MockMasterClock(); + private static readonly ILogger logger = LogManager.CreateNullLogger(); + private readonly MockMasterClock clock = new MockMasterClock(); - [Fact] - public void VarDiff_Should_Honor_MaxDelta_When_Adjusting_Up() - { - var vdm = new VarDiffManager(config, clock); - var ctx = new WorkerContextBase {Difficulty = 7500, VarDiff = new VarDiffContext() }; + [Fact] + public void VarDiff_Should_Honor_MaxDelta_When_Adjusting_Up() + { + var vdm = new VarDiffManager(config, clock); + var ctx = new WorkerContextBase {Difficulty = 7500, VarDiff = new VarDiffContext() }; - var shares = new List { 2, 3, 4 }; - var newDiff = vdm.Update(ctx, shares, string.Empty, logger); - Assert.NotNull(newDiff); - Assert.True(newDiff.Value.EqualsDigitPrecision3(8500)); - } + var shares = new List { 2, 3, 4 }; + var newDiff = vdm.Update(ctx, shares, string.Empty, logger); + Assert.NotNull(newDiff); + Assert.True(newDiff.Value.EqualsDigitPrecision3(8500)); + } - [Fact] - public void VarDiff_Should_Honor_MaxDelta_When_Adjusting_Down() - { - var vdm = new VarDiffManager(config, clock); - var ctx = new WorkerContextBase { Difficulty = 7500, VarDiff = new VarDiffContext() }; + [Fact] + public void VarDiff_Should_Honor_MaxDelta_When_Adjusting_Down() + { + var vdm = new VarDiffManager(config, clock); + var ctx = new WorkerContextBase { Difficulty = 7500, VarDiff = new VarDiffContext() }; - var shares = new List { 2000000000, 3000000000, 4000000000 }; - var newDiff = vdm.Update(ctx, shares, string.Empty, logger); - Assert.NotNull(newDiff); - Assert.True(newDiff.Value.EqualsDigitPrecision3(6500)); - } + var shares = new List { 2000000000, 3000000000, 4000000000 }; + var newDiff = vdm.Update(ctx, shares, string.Empty, logger); + Assert.NotNull(newDiff); + Assert.True(newDiff.Value.EqualsDigitPrecision3(6500)); + } - [Fact] - public void VarDiff_Should_Honor_MaxDiff_When_Adjusting_Up() - { - var vdm = new VarDiffManager(config, clock); - var ctx = new WorkerContextBase { Difficulty = 9500, VarDiff = new VarDiffContext() }; + [Fact] + public void VarDiff_Should_Honor_MaxDiff_When_Adjusting_Up() + { + var vdm = new VarDiffManager(config, clock); + var ctx = new WorkerContextBase { Difficulty = 9500, VarDiff = new VarDiffContext() }; - var shares = new List { 2, 3, 4 }; - var newDiff = vdm.Update(ctx, shares, string.Empty, logger); - Assert.NotNull(newDiff); - Assert.True(newDiff.Value.EqualsDigitPrecision3(10000)); - } + var shares = new List { 2, 3, 4 }; + var newDiff = vdm.Update(ctx, shares, string.Empty, logger); + Assert.NotNull(newDiff); + Assert.True(newDiff.Value.EqualsDigitPrecision3(10000)); + } - [Fact] - public void VarDiff_Should_Honor_MinDiff_When_Adjusting_Down() - { - var vdm = new VarDiffManager(config, clock); - var ctx = new WorkerContextBase { Difficulty = 1500, VarDiff = new VarDiffContext() }; + [Fact] + public void VarDiff_Should_Honor_MinDiff_When_Adjusting_Down() + { + var vdm = new VarDiffManager(config, clock); + var ctx = new WorkerContextBase { Difficulty = 1500, VarDiff = new VarDiffContext() }; - var shares = new List { 2000000000, 3000000000, 4000000000 }; - var newDiff = vdm.Update(ctx, shares, string.Empty, logger); - Assert.NotNull(newDiff); - Assert.True(newDiff.Value.EqualsDigitPrecision3(1000)); - } -*/ + var shares = new List { 2000000000, 3000000000, 4000000000 }; + var newDiff = vdm.Update(ctx, shares, string.Empty, logger); + Assert.NotNull(newDiff); + Assert.True(newDiff.Value.EqualsDigitPrecision3(1000)); + } + */ } } From bf73759df563a5dd20980bf90fce90ba98d425ed Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Thu, 4 Apr 2019 13:48:10 +0200 Subject: [PATCH 122/178] Add .editorconfig to solution --- src/Miningcore.sln | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Miningcore.sln b/src/Miningcore.sln index defb5c423..e34a73fd7 100644 --- a/src/Miningcore.sln +++ b/src/Miningcore.sln @@ -1,12 +1,17 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26730.3 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28729.10 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Miningcore", "Miningcore\Miningcore.csproj", "{A427248A-B5E1-4808-9883-BC2AD68EE997}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Miningcore.Tests", "Miningcore.Tests\Miningcore.Tests.csproj", "{DCDE9CE6-84B8-42FE-AA55-2A3909A5E757}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{71672AAD-51F8-49EC-9EFD-E504D65A765A}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU From e4a8d9eb4c1276d6e6c8b99cf14f19c582df4bdf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 4 Apr 2019 14:07:02 +0200 Subject: [PATCH 123/178] Bump NBitcoin from 4.1.1.96 to 4.1.1.97 in /src/Miningcore (#594) Bumps [NBitcoin](https://github.com/MetacoSA/NBitcoin) from 4.1.1.96 to 4.1.1.97. - [Release notes](https://github.com/MetacoSA/NBitcoin/releases) - [Commits](https://github.com/MetacoSA/NBitcoin/compare/v4.1.1.96...v4.1.1.97) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index f9068489a..5efa5b57c 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -63,7 +63,7 @@ - + From b3d8e2e7192db50c47ddf276330569ee8fe48f45 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 15 Apr 2019 11:12:04 +0200 Subject: [PATCH 124/178] Bump FluentValidation from 8.2.0 to 8.2.3 in /src/Miningcore (#609) Bumps [FluentValidation](https://github.com/JeremySkinner/fluentvalidation) from 8.2.0 to 8.2.3. - [Release notes](https://github.com/JeremySkinner/fluentvalidation/releases) - [Changelog](https://github.com/JeremySkinner/FluentValidation/blob/master/Changelog.txt) - [Commits](https://github.com/JeremySkinner/fluentvalidation/compare/8.2.0...8.2.3) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 5efa5b57c..086554dce 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -54,7 +54,7 @@ - + From 50ee366ad958490ed95af0a489d85224124b4b73 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 15 Apr 2019 11:12:18 +0200 Subject: [PATCH 125/178] Bump prometheus-net from 3.1.0 to 3.1.1 in /src/Miningcore (#608) Bumps [prometheus-net](https://github.com/prometheus-net/prometheus-net) from 3.1.0 to 3.1.1. - [Release notes](https://github.com/prometheus-net/prometheus-net/releases) - [Changelog](https://github.com/prometheus-net/prometheus-net/blob/master/History) - [Commits](https://github.com/prometheus-net/prometheus-net/compare/v3.1.0...v3.1.1) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 086554dce..ee70f8c76 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -71,7 +71,7 @@ - + From 70e867907dbecd9a8539ce10f2a422fc7f4d48c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 15 Apr 2019 11:12:43 +0200 Subject: [PATCH 126/178] Bump Npgsql from 4.0.4 to 4.0.6 in /src/Miningcore (#603) Bumps [Npgsql](https://github.com/npgsql/npgsql) from 4.0.4 to 4.0.6. - [Release notes](https://github.com/npgsql/npgsql/releases) - [Commits](https://github.com/npgsql/npgsql/compare/v4.0.4...v4.0.6) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index ee70f8c76..bc5dc9d47 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -68,7 +68,7 @@ - + From 96243b7e7b1348ddbf6378d4752ea4a2c00531af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 6 May 2019 13:09:52 +0200 Subject: [PATCH 127/178] Bump NBitcoin from 4.1.1.97 to 4.1.2.12 in /src/Miningcore (#619) Bumps [NBitcoin](https://github.com/MetacoSA/NBitcoin) from 4.1.1.97 to 4.1.2.12. - [Release notes](https://github.com/MetacoSA/NBitcoin/releases) - [Commits](https://github.com/MetacoSA/NBitcoin/compare/v4.1.1.97...v4.1.2.12) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index bc5dc9d47..e79d02c5f 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -63,7 +63,7 @@ - + From 38912d86bc2800aa99612cfb6545601ae6ce5266 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 6 May 2019 13:10:14 +0200 Subject: [PATCH 128/178] Bump NLog from 4.6.1 to 4.6.3 in /src/Miningcore (#618) Bumps [NLog](https://github.com/NLog/NLog) from 4.6.1 to 4.6.3. - [Release notes](https://github.com/NLog/NLog/releases) - [Changelog](https://github.com/NLog/NLog/blob/dev/CHANGELOG.md) - [Commits](https://github.com/NLog/NLog/compare/v4.6.1...v4.6.3) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index e79d02c5f..8ffed98ff 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -66,7 +66,7 @@ - + From 9b841914336b6296fd29ec740a0c9a40352ac9e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 6 May 2019 13:10:47 +0200 Subject: [PATCH 129/178] Bump prometheus-net.AspNetCore from 3.1.0 to 3.1.2 in /src/Miningcore (#615) Bumps [prometheus-net.AspNetCore](https://github.com/prometheus-net/prometheus-net) from 3.1.0 to 3.1.2. - [Release notes](https://github.com/prometheus-net/prometheus-net/releases) - [Changelog](https://github.com/prometheus-net/prometheus-net/blob/master/History) - [Commits](https://github.com/prometheus-net/prometheus-net/compare/v3.1.0...v3.1.2) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 8ffed98ff..18883ec8f 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -70,7 +70,7 @@ - + From ccbf13d9abc979e6537a34e7a53c45f4d1c5be15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 6 May 2019 13:11:14 +0200 Subject: [PATCH 130/178] Bump MailKit from 2.1.3 to 2.1.4 in /src/Miningcore (#606) Bumps [MailKit](https://github.com/jstedfast/MailKit) from 2.1.3 to 2.1.4. - [Release notes](https://github.com/jstedfast/MailKit/releases) - [Changelog](https://github.com/jstedfast/MailKit/blob/master/ReleaseNotes.md) - [Commits](https://github.com/jstedfast/MailKit/compare/2.1.3...2.1.4) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 18883ec8f..60f8227f3 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -56,7 +56,7 @@ - + From 41203ef762a2db8819afd89664f78255360ecddd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 6 May 2019 13:11:24 +0200 Subject: [PATCH 131/178] Bump morelinq from 3.1.0 to 3.1.1 in /src/Miningcore (#599) Bumps [morelinq](https://github.com/morelinq/MoreLINQ) from 3.1.0 to 3.1.1. - [Release notes](https://github.com/morelinq/MoreLINQ/releases) - [Commits](https://github.com/morelinq/MoreLINQ/compare/v3.1.0...v3.1.1) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 60f8227f3..168c1dd04 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -62,7 +62,7 @@ - + From 491a3637b056401ba24692728fda3c2bb4441eb1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 6 May 2019 13:11:44 +0200 Subject: [PATCH 132/178] Bump Newtonsoft.Json from 12.0.1 to 12.0.2 in /src/Miningcore (#612) Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 12.0.1 to 12.0.2. - [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases) - [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/12.0.1...12.0.2) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 168c1dd04..c31a3d418 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -65,7 +65,7 @@ - + From eaf9ec9aa54cbfd7534214690e5772c2848f5697 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 6 May 2019 13:11:58 +0200 Subject: [PATCH 133/178] Bump FluentValidation.ValidatorAttribute in /src/Miningcore (#613) Bumps [FluentValidation.ValidatorAttribute](https://github.com/JeremySkinner/fluentvalidation) from 8.2.0 to 8.3.0. - [Release notes](https://github.com/JeremySkinner/fluentvalidation/releases) - [Changelog](https://github.com/JeremySkinner/FluentValidation/blob/master/Changelog.txt) - [Commits](https://github.com/JeremySkinner/fluentvalidation/compare/8.2.0...8.3.0) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index c31a3d418..03fd8184b 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -53,7 +53,7 @@ - + From bed74ae70cfb368ae811ee1372480d6f82af729c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 6 May 2019 13:12:09 +0200 Subject: [PATCH 134/178] Bump System.Reactive from 4.1.3 to 4.1.5 in /src/Miningcore (#607) Bumps [System.Reactive](https://github.com/dotnet/reactive) from 4.1.3 to 4.1.5. - [Release notes](https://github.com/dotnet/reactive/releases) - [Commits](https://github.com/dotnet/reactive/compare/rxnet-v4.1.3...rxnet-v4.1.5) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 03fd8184b..ea2c8e0cb 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -74,7 +74,7 @@ - + From 94345badbf697fab024ce423e33b51a237720ae7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 6 May 2019 13:16:59 +0200 Subject: [PATCH 135/178] Bump prometheus-net from 3.1.1 to 3.1.2 in /src/Miningcore (#614) Bumps [prometheus-net](https://github.com/prometheus-net/prometheus-net) from 3.1.1 to 3.1.2. - [Release notes](https://github.com/prometheus-net/prometheus-net/releases) - [Changelog](https://github.com/prometheus-net/prometheus-net/blob/master/History) - [Commits](https://github.com/prometheus-net/prometheus-net/compare/v3.1.1...v3.1.2) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index ea2c8e0cb..5f95c4956 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -71,7 +71,7 @@ - + From 919b1611516e652fc4e9ef5a0d5b27cb540556f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 6 May 2019 13:17:08 +0200 Subject: [PATCH 136/178] Bump McMaster.Extensions.CommandLineUtils in /src/Miningcore (#605) Bumps [McMaster.Extensions.CommandLineUtils](https://github.com/natemcmaster/CommandLineUtils) from 2.3.3 to 2.3.4. - [Release notes](https://github.com/natemcmaster/CommandLineUtils/releases) - [Changelog](https://github.com/natemcmaster/CommandLineUtils/blob/master/CHANGELOG.md) - [Commits](https://github.com/natemcmaster/CommandLineUtils/compare/v2.3.3...v2.3.4) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 5f95c4956..0a2c8b8a4 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -57,7 +57,7 @@ - + From d9ad99ec2fe79a9c3510179b3cb6cee8214af8bd Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 6 May 2019 13:21:46 +0200 Subject: [PATCH 137/178] Upgrade FluentValidation package --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 0a2c8b8a4..572e5fed0 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -54,7 +54,7 @@ - + From d49be478429652af95b66f5ad0991cf5f656a8e4 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 6 May 2019 13:26:19 +0200 Subject: [PATCH 138/178] Upgrade AutoMapper package --- src/Miningcore/Miningcore.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 572e5fed0..1d918ef0b 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -1,4 +1,4 @@ - + Exe @@ -51,7 +51,7 @@ - + From 13dcf85afe986368eb8e335294334baeeb509705 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 6 May 2019 14:23:47 +0200 Subject: [PATCH 139/178] Update for VS2019 --- libs/runtimes/win-x64/libcryptonight.dll | Bin 204800 -> 211456 bytes libs/runtimes/win-x64/libcryptonote.dll | Bin 386048 -> 391168 bytes libs/runtimes/win-x64/libmultihash.dll | Bin 1189376 -> 1203200 bytes .../libcryptonight/libcryptonight.vcxproj | 10 +++++----- .../libcryptonote/libcryptonote.vcxproj | 10 +++++----- .../libmultihash/equi/equihashverify.cc | 4 ++++ src/Native/libmultihash/libmultihash.vcxproj | 10 +++++----- 7 files changed, 19 insertions(+), 15 deletions(-) diff --git a/libs/runtimes/win-x64/libcryptonight.dll b/libs/runtimes/win-x64/libcryptonight.dll index 427ce9fcccba92a692a686dd32f7b6e090b20f1f..deb59a01fbbedaba541aace4ea88d681073a043f 100644 GIT binary patch delta 86290 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 diff --git a/libs/runtimes/win-x64/libcryptonote.dll b/libs/runtimes/win-x64/libcryptonote.dll index 5d73a4576f7ba16ff867cabf7ed46dd898d0d6b5..cdd76dc39c38e208b3584d7e9bc0817c0965018a 100644 GIT binary patch delta 198098 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 GqW=NY^fEyJ delta 192053 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%0Db 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 diff --git a/libs/runtimes/win-x64/libmultihash.dll b/libs/runtimes/win-x64/libmultihash.dll index feda36a76d910c35a3363006447934e78d939f2b..0c261587ef98918ff333a6b961c8f62715c5c34d 100644 GIT binary patch delta 345460 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�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 delta 331192 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

tRl9Ag@I~jY? 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 JH7gQc`+twR+!p`< diff --git a/src/Native/libcryptonight/libcryptonight.vcxproj b/src/Native/libcryptonight/libcryptonight.vcxproj index 520aa16cb..633ea3605 100644 --- a/src/Native/libcryptonight/libcryptonight.vcxproj +++ b/src/Native/libcryptonight/libcryptonight.vcxproj @@ -23,33 +23,33 @@ {3D1C939F-36D2-4942-A125-2C7E6FF2833F} Win32Proj netmultihashnative - 10.0.15063.0 + 10.0 libcryptonight DynamicLibrary true - v141 + v142 Unicode DynamicLibrary false - v141 + v142 true Unicode DynamicLibrary true - v141 + v142 Unicode DynamicLibrary false - v141 + v142 true Unicode diff --git a/src/Native/libcryptonote/libcryptonote.vcxproj b/src/Native/libcryptonote/libcryptonote.vcxproj index 17d41aa6b..9e9b7734f 100644 --- a/src/Native/libcryptonote/libcryptonote.vcxproj +++ b/src/Native/libcryptonote/libcryptonote.vcxproj @@ -23,33 +23,33 @@ {2DE74E14-BF6D-4046-951B-8EBC8A1BA009} Win32Proj netmultihashnative - 10.0.15063.0 + 10.0 libcryptonote DynamicLibrary true - v141 + v142 Unicode DynamicLibrary false - v141 + v142 true Unicode DynamicLibrary true - v141 + v142 Unicode DynamicLibrary false - v141 + v142 true Unicode diff --git a/src/Native/libmultihash/equi/equihashverify.cc b/src/Native/libmultihash/equi/equihashverify.cc index 05b6dbe35..501d265fb 100644 --- a/src/Native/libmultihash/equi/equihashverify.cc +++ b/src/Native/libmultihash/equi/equihashverify.cc @@ -2,6 +2,10 @@ #include "crypto/equihash.h" #include "equihashverify.h" +#ifdef _WIN32 +#include +#endif + static const char *default_personalization = "ZcashPoW"; bool verifyEH_96_5(const char *hdr, const std::vector &soln, const char *personalization) diff --git a/src/Native/libmultihash/libmultihash.vcxproj b/src/Native/libmultihash/libmultihash.vcxproj index 1e6567d3a..512e19499 100644 --- a/src/Native/libmultihash/libmultihash.vcxproj +++ b/src/Native/libmultihash/libmultihash.vcxproj @@ -23,33 +23,33 @@ {2DE74E14-BF6D-4046-951B-8EBC8A1BA009} Win32Proj netmultihashnative - 10.0.15063.0 + 10.0 libmultihash DynamicLibrary true - v141 + v142 Unicode DynamicLibrary false - v141 + v142 true Unicode DynamicLibrary true - v141 + v142 Unicode DynamicLibrary false - v141 + v142 true Unicode From b08470deef2c7824e74b9440ee9d764517123b63 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 6 May 2019 16:16:04 +0200 Subject: [PATCH 140/178] Added OdoCrypt support --- libs/runtimes/win-x64/libmultihash.dll | Bin 1203200 -> 1211904 bytes src/Miningcore.Tests/Crypto/HashingTests.cs | 11 + .../Crypto/Hashing/Algorithms/OdoCrypt.cs | 45 ++ src/Miningcore/Native/LibMultihash.cs | 3 + src/Native/libmultihash/KeccakP-800-SnP.h | 41 ++ .../libmultihash/KeccakP-800-reference.c | 421 ++++++++++++++++++ src/Native/libmultihash/Makefile | 4 +- src/Native/libmultihash/brg_endian.h | 142 ++++++ src/Native/libmultihash/exports.cpp | 6 + src/Native/libmultihash/hashodo.h | 31 ++ src/Native/libmultihash/libmultihash.vcxproj | 6 + .../libmultihash/libmultihash.vcxproj.filters | 18 + src/Native/libmultihash/odocrypt.cpp | 302 +++++++++++++ src/Native/libmultihash/odocrypt.h | 97 ++++ 14 files changed, 1125 insertions(+), 2 deletions(-) create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/OdoCrypt.cs create mode 100644 src/Native/libmultihash/KeccakP-800-SnP.h create mode 100644 src/Native/libmultihash/KeccakP-800-reference.c create mode 100644 src/Native/libmultihash/brg_endian.h create mode 100644 src/Native/libmultihash/hashodo.h create mode 100644 src/Native/libmultihash/odocrypt.cpp create mode 100644 src/Native/libmultihash/odocrypt.h diff --git a/libs/runtimes/win-x64/libmultihash.dll b/libs/runtimes/win-x64/libmultihash.dll index 0c261587ef98918ff333a6b961c8f62715c5c34d..d87d8a69956e4f330d322aa88c412e09a73aa4b3 100644 GIT binary patch delta 180256 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%0DopH5-hDq3Tf~5g=eB4Q8iI(Tpkw=<4)FG;+F! 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

p8$D$#_qr?9m!6<@xlQPJ^A&_%+ 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 M41P7Z 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 vjz9L;3iTFCdQ*YrSLbk@mF_?P>^tb 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 data, Span result, params object[] extra) + { + Contract.Requires(data.Length <= 80, $"{nameof(data)} must be less or equal 80 bytes"); + Contract.Requires(result.Length >= 32, $"{nameof(result)} must be greater or equal 32 bytes"); + + var key = (uint) extra[0]; + + fixed (byte* input = data) + { + fixed (byte* output = result) + { + LibMultihash.odocrypt(input, output, (uint) data.Length, key); + } + } + } + } +} diff --git a/src/Miningcore/Native/LibMultihash.cs b/src/Miningcore/Native/LibMultihash.cs index c5434b1f0..8ae912618 100644 --- a/src/Miningcore/Native/LibMultihash.cs +++ b/src/Miningcore/Native/LibMultihash.cs @@ -52,6 +52,9 @@ public static unsafe class LibMultihash [DllImport("libmultihash", EntryPoint = "x21s_export", CallingConvention = CallingConvention.Cdecl)] public static extern int x21s(byte* input, void* output, uint inputLength); + [DllImport("libmultihash", EntryPoint = "odocrypt_export", CallingConvention = CallingConvention.Cdecl)] + public static extern int odocrypt(byte* input, void* output, uint inputLength, uint key); + [DllImport("libmultihash", EntryPoint = "neoscrypt_export", CallingConvention = CallingConvention.Cdecl)] public static extern int neoscrypt(byte* input, void* output, uint inputLength, uint profile); diff --git a/src/Native/libmultihash/KeccakP-800-SnP.h b/src/Native/libmultihash/KeccakP-800-SnP.h new file mode 100644 index 000000000..4b2556c06 --- /dev/null +++ b/src/Native/libmultihash/KeccakP-800-SnP.h @@ -0,0 +1,41 @@ +/* +Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, +Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby +denoted as "the implementer". + +For more information, feedback or questions, please refer to our websites: +http://keccak.noekeon.org/ +http://keyak.noekeon.org/ +http://ketje.noekeon.org/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#ifndef _KeccakP_800_SnP_h_ +#define _KeccakP_800_SnP_h_ + +/** For the documentation, see SnP-documentation.h. + */ + +#define KeccakP800_implementation "32-bit reference implementation" +#define KeccakP800_stateSizeInBytes 100 +#define KeccakP800_stateAlignment 4 + +#ifdef KeccakReference +void KeccakP800_StaticInitialize( void ); +#else +#define KeccakP800_StaticInitialize() +#endif +void KeccakP800_Initialize(void *state); +void KeccakP800_AddByte(void *state, unsigned char data, unsigned int offset); +void KeccakP800_AddBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length); +void KeccakP800_OverwriteBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length); +void KeccakP800_OverwriteWithZeroes(void *state, unsigned int byteCount); +void KeccakP800_Permute_12rounds(void *state); +void KeccakP800_Permute_22rounds(void *state); +void KeccakP800_ExtractBytes(const void *state, unsigned char *data, unsigned int offset, unsigned int length); +void KeccakP800_ExtractAndAddBytes(const void *state, const unsigned char *input, unsigned char *output, unsigned int offset, unsigned int length); + +#endif diff --git a/src/Native/libmultihash/KeccakP-800-reference.c b/src/Native/libmultihash/KeccakP-800-reference.c new file mode 100644 index 000000000..b71a4889d --- /dev/null +++ b/src/Native/libmultihash/KeccakP-800-reference.c @@ -0,0 +1,421 @@ +/* +Implementation by the Keccak Team, namely, Guido Bertoni, Joan Daemen, +Michaël Peeters, Gilles Van Assche and Ronny Van Keer, +hereby denoted as "the implementer". + +For more information, feedback or questions, please refer to our website: +https://keccak.team/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ + +--- + +This file implements Keccak-p[800] in a SnP-compatible way. +Please refer to SnP-documentation.h for more details. + +This implementation comes with KeccakP-800-SnP.h in the same folder. +Please refer to LowLevel.build for the exact list of other files it must be combined with. +*/ + +#include +#include +#include +#include +#include "brg_endian.h" +#ifdef KeccakReference +#include "displayIntermediateValues.h" +#endif + +typedef unsigned char UINT8; +typedef unsigned int UINT32; +typedef UINT32 tKeccakLane; + +#define maxNrRounds 22 +#define nrLanes 25 +#define index(x, y) (((x)%5)+5*((y)%5)) + +#ifdef KeccakReference + +static tKeccakLane KeccakRoundConstants[maxNrRounds]; +static unsigned int KeccakRhoOffsets[nrLanes]; + +/* ---------------------------------------------------------------- */ + +void KeccakP800_InitializeRoundConstants(void); +void KeccakP800_InitializeRhoOffsets(void); +static int LFSR86540(UINT8 *LFSR); + +void KeccakP800_StaticInitialize(void) +{ + if (sizeof(tKeccakLane) != 4) { + printf("tKeccakLane should be 32-bit wide\n"); + abort(); + } + KeccakP800_InitializeRoundConstants(); + KeccakP800_InitializeRhoOffsets(); +} + +void KeccakP800_InitializeRoundConstants(void) +{ + UINT8 LFSRstate = 0x01; + unsigned int i, j, bitPosition; + + for(i=0; i> (8*j)) & 0xFF; +} + +void KeccakP800OnWords(tKeccakLane *state, unsigned int nrRounds) +{ + unsigned int i; + +#ifdef KeccakReference + displayStateAsLanes(3, "Same, with lanes as 32-bit words", state, 800); +#endif + + for(i=(maxNrRounds-nrRounds); i> (sizeof(tKeccakLane)*8-offset))) : a) + +static void theta(tKeccakLane *A) +{ + unsigned int x, y; + tKeccakLane C[5], D[5]; + + for(x=0; x<5; x++) { + C[x] = 0; + for(y=0; y<5; y++) + C[x] ^= A[index(x, y)]; + } + for(x=0; x<5; x++) + D[x] = ROL32(C[(x+1)%5], 1) ^ C[(x+4)%5]; + for(x=0; x<5; x++) + for(y=0; y<5; y++) + A[index(x, y)] ^= D[x]; +} + +static void rho(tKeccakLane *A) +{ + unsigned int x, y; + + for(x=0; x<5; x++) for(y=0; y<5; y++) + A[index(x, y)] = ROL32(A[index(x, y)], KeccakRhoOffsets[index(x, y)]); +} + +static void pi(tKeccakLane *A) +{ + unsigned int x, y; + tKeccakLane tempA[25]; + + for(x=0; x<5; x++) for(y=0; y<5; y++) + tempA[index(x, y)] = A[index(x, y)]; + for(x=0; x<5; x++) for(y=0; y<5; y++) + A[index(0*x+1*y, 2*x+3*y)] = tempA[index(x, y)]; +} + +static void chi(tKeccakLane *A) +{ + unsigned int x, y; + tKeccakLane C[5]; + + for(y=0; y<5; y++) { + for(x=0; x<5; x++) + C[x] = A[index(x, y)] ^ ((~A[index(x+1, y)]) & A[index(x+2, y)]); + for(x=0; x<5; x++) + A[index(x, y)] = C[x]; + } +} + +static void iota(tKeccakLane *A, unsigned int indexRound) +{ + A[index(0, 0)] ^= KeccakRoundConstants[indexRound]; +} + +/* ---------------------------------------------------------------- */ + +void KeccakP800_ExtractBytes(const void *state, unsigned char *data, unsigned int offset, unsigned int length) +{ + assert(offset < 100); + assert(offset+length <= 100); + memcpy(data, (unsigned char*)state+offset, length); +} + +/* ---------------------------------------------------------------- */ + +void KeccakP800_ExtractAndAddBytes(const void *state, const unsigned char *input, unsigned char *output, unsigned int offset, unsigned int length) +{ + unsigned int i; + + assert(offset < 100); + assert(offset+length <= 100); + for(i=0; i +#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) +# include +#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ + defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) +# include +#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) +# if !defined( __MINGW32__ ) && !defined( _AIX ) +# include +# if !defined( __BEOS__ ) +# include +# endif +# endif +#endif +#endif + +/* Now attempt to set the define for platform byte order using any */ +/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ +/* seem to encompass most endian symbol definitions */ + +#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) +# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) +# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( _BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( _LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) +# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( __BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( __LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) +# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( __BIG_ENDIAN__ ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( __LITTLE_ENDIAN__ ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +/* if the platform byte order could not be determined, then try to */ +/* set this define using common machine defines */ +#if !defined(PLATFORM_BYTE_ORDER) + +#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ + defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ + defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ + defined( vax ) || defined( vms ) || defined( VMS ) || \ + defined( __VMS ) || defined( _M_X64 ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN + +#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ + defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ + defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ + defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ + defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ + defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ + defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN + +#elif defined(__arm__) +# ifdef __BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# else +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif 1 /* **** EDIT HERE IF NECESSARY **** */ +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#elif 0 /* **** EDIT HERE IF NECESSARY **** */ +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#else +# error Please edit lines 132 or 134 in brg_endian.h to set the platform byte order +#endif + +#endif + +#endif diff --git a/src/Native/libmultihash/exports.cpp b/src/Native/libmultihash/exports.cpp index 09f726800..8f2a328fd 100644 --- a/src/Native/libmultihash/exports.cpp +++ b/src/Native/libmultihash/exports.cpp @@ -47,6 +47,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "x16s.h" #include "x22i.h" #include "x21s.h" +#include "hashodo.h" #include "equi/equihashverify.h" #include "libethash/sha3.h" #include "libethash/internal.h" @@ -227,6 +228,11 @@ extern "C" MODULE_API void x21s_export(const char* input, char* output, uint32_t x21s_hash(input, output, input_len); } +extern "C" MODULE_API void odocrypt_export(const char* input, char* output, uint32_t input_len, uint32_t key) +{ + odocrypt_hash(input, output, input_len, key); +} + extern "C" MODULE_API void x16s_export(const char* input, char* output, uint32_t input_len) { x16s_hash(input, output, input_len); diff --git a/src/Native/libmultihash/hashodo.h b/src/Native/libmultihash/hashodo.h new file mode 100644 index 000000000..da725fe71 --- /dev/null +++ b/src/Native/libmultihash/hashodo.h @@ -0,0 +1,31 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2018 The DigiByte developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef HASH_ODO +#define HASH_ODO + +#include +#include + +#include "odocrypt.h" +extern "C" { +#include "KeccakP-800-SnP.h" +} + +inline void odocrypt_hash(const char* input, char* output, uint32_t len, uint32_t key) +{ + char cipher[KeccakP800_stateSizeInBytes] = {}; + + assert(len <= OdoCrypt::DIGEST_SIZE); + assert(OdoCrypt::DIGEST_SIZE < KeccakP800_stateSizeInBytes); + memcpy(cipher, static_cast(input), len); + cipher[len] = 1; + + OdoCrypt(key).Encrypt(cipher, cipher); + KeccakP800_Permute_12rounds(cipher); + memcpy(output, cipher, 32); +} + +#endif diff --git a/src/Native/libmultihash/libmultihash.vcxproj b/src/Native/libmultihash/libmultihash.vcxproj index 512e19499..585c78219 100644 --- a/src/Native/libmultihash/libmultihash.vcxproj +++ b/src/Native/libmultihash/libmultihash.vcxproj @@ -172,6 +172,7 @@ + @@ -195,9 +196,11 @@ + + @@ -212,6 +215,7 @@ + @@ -288,6 +292,7 @@ + @@ -299,6 +304,7 @@ + diff --git a/src/Native/libmultihash/libmultihash.vcxproj.filters b/src/Native/libmultihash/libmultihash.vcxproj.filters index 2cfe7add0..dedc78527 100644 --- a/src/Native/libmultihash/libmultihash.vcxproj.filters +++ b/src/Native/libmultihash/libmultihash.vcxproj.filters @@ -284,6 +284,18 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + @@ -529,6 +541,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/src/Native/libmultihash/odocrypt.cpp b/src/Native/libmultihash/odocrypt.cpp new file mode 100644 index 000000000..dc5bee209 --- /dev/null +++ b/src/Native/libmultihash/odocrypt.cpp @@ -0,0 +1,302 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2018 The DigiByte developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "odocrypt.h" + +#include + +struct OdoRandom +{ + // LCG parameters from Knuth + const static uint64_t BASE_MULTIPLICAND = 6364136223846793005ull; + const static uint64_t BASE_ADDEND = 1442695040888963407ull; + + OdoRandom(uint32_t seed): + current(seed), + multiplicand(1), + addend(0) + {} + + // For a standard LCG, every seed produces the same sequence, but from a different + // starting point. This generator gives the 1st, 3rd, 6th, 10th, etc output from + // a standard LCG. This ensures that every seed produces a unique sequence. + inline uint32_t NextInt() + { + addend += multiplicand * BASE_ADDEND; + multiplicand *= BASE_MULTIPLICAND; + current = current * multiplicand + addend; + return current >> 32; + } + + inline uint64_t NextLong() + { + uint64_t hi = NextInt(); + return (hi << 32) | NextInt(); + } + + inline int Next(int N) + { + return ((uint64_t)NextInt() * N) >> 32; + } + + template + void Permutation(T (&arr)[sz]) + { + for (size_t i = 0; i < sz; i++) + arr[i] = i; + for (size_t i = 1; i < sz; i++) + std::swap(arr[i], arr[Next(i+1)]); + } + + uint64_t current; + uint64_t multiplicand; + uint64_t addend; +}; + +OdoCrypt::OdoCrypt(uint32_t key) +{ + OdoRandom r(key); + + // Randomize each s-box + for (int i = 0; i < SMALL_SBOX_COUNT; i++) + { + r.Permutation(Sbox1[i]); + } + for (int i = 0; i < LARGE_SBOX_COUNT; i++) + { + r.Permutation(Sbox2[i]); + } + + // Randomize each p-box + for (int i = 0; i < 2; i++) + { + Pbox& perm = Permutation[i]; + for (int j = 0; j < PBOX_SUBROUNDS; j++) + for (int k = 0; k < STATE_SIZE/2; k++) + perm.mask[j][k] = r.NextLong(); + for (int j = 0; j < PBOX_SUBROUNDS-1; j++) + for (int k = 0; k < STATE_SIZE/2; k++) + perm.rotation[j][k] = r.Next(63) + 1; + } + + // Randomize rotations + // Rotations must be distinct, non-zero, and have odd sum + { + int bits[WORD_BITS-1]; + r.Permutation(bits); + int sum = 0; + for (int j = 0; j < ROTATION_COUNT-1; j++) + { + Rotations[j] = bits[j] + 1; + sum += Rotations[j]; + } + for (int j = ROTATION_COUNT-1; ; j++) + { + if ((bits[j] + 1 + sum) % 2) + { + Rotations[ROTATION_COUNT-1] = bits[j] + 1; + break; + } + } + } + + // Randomize each round key + for (int i = 0; i < ROUNDS; i++) + RoundKey[i] = r.Next(1 << STATE_SIZE); +} + +void OdoCrypt::Encrypt(char cipher[DIGEST_SIZE], const char plain[DIGEST_SIZE]) const +{ + uint64_t state[STATE_SIZE]; + Unpack(state, plain); + PreMix(state); + for (int round = 0; round < ROUNDS; round++) + { + ApplyPbox(state, Permutation[0]); + ApplySboxes(state, Sbox1, Sbox2); + ApplyPbox(state, Permutation[1]); + ApplyRotations(state, Rotations); + ApplyRoundKey(state, RoundKey[round]); + } + Pack(state, cipher); +} + +template +void InvertMapping(T (&res)[sz1][sz2], const T (&mapping)[sz1][sz2]) +{ + for (size_t i = 0; i < sz1; i++) + for (size_t j = 0; j < sz2; j++) + res[i][mapping[i][j]] = j; +} + +void OdoCrypt::Decrypt(char plain[DIGEST_SIZE], const char cipher[DIGEST_SIZE]) const +{ + uint8_t invSbox1[SMALL_SBOX_COUNT][1 << SMALL_SBOX_WIDTH]; + uint16_t invSbox2[LARGE_SBOX_COUNT][1 << LARGE_SBOX_WIDTH]; + + InvertMapping(invSbox1, Sbox1); + InvertMapping(invSbox2, Sbox2); + + uint64_t state[STATE_SIZE]; + Unpack(state, cipher); + for (int round = ROUNDS-1; round >= 0; round--) + { + ApplyRoundKey(state, RoundKey[round]); + // LCM(STATE_SIZE, WORD_BITS)-1 is enough iterations, but this will do. + for (int i = 0; i < STATE_SIZE*WORD_BITS-1; i++) + ApplyRotations(state, Rotations); + ApplyInvPbox(state, Permutation[1]); + ApplySboxes(state, invSbox1, invSbox2); + ApplyInvPbox(state, Permutation[0]); + } + PreMix(state); + Pack(state, plain); +} + +void OdoCrypt::Unpack(uint64_t state[STATE_SIZE], const char bytes[DIGEST_SIZE]) +{ + std::fill(state, state+STATE_SIZE, 0); + for (int i = 0; i < STATE_SIZE; i++) + { + for (int j = 0; j < 8; j++) + { + state[i] |= (uint64_t)(uint8_t)bytes[8*i + j] << (8*j); + } + } +} + +void OdoCrypt::Pack(const uint64_t state[STATE_SIZE], char bytes[DIGEST_SIZE]) +{ + std::fill(bytes, bytes+DIGEST_SIZE, 0); + for (int i = 0; i < STATE_SIZE; i++) + { + for (int j = 0; j < 8; j++) + { + bytes[8*i + j] = (state[i] >> (8*j)) & 0xff; + } + } +} + +void OdoCrypt::PreMix(uint64_t state[STATE_SIZE]) +{ + uint64_t total = 0; + for (int i = 0; i < STATE_SIZE; i++) + total ^= state[i]; + total ^= total >> 32; + for (int i = 0; i < STATE_SIZE; i++) + state[i] ^= total; +} + +void OdoCrypt::ApplySboxes( + uint64_t state[STATE_SIZE], + const uint8_t sbox1[SMALL_SBOX_COUNT][1 << SMALL_SBOX_WIDTH], + const uint16_t sbox2[LARGE_SBOX_COUNT][1 << LARGE_SBOX_WIDTH]) +{ + const static uint64_t MASK1 = (1 << SMALL_SBOX_WIDTH) - 1; + const static uint64_t MASK2 = (1 << LARGE_SBOX_WIDTH) - 1; + + int smallSboxIndex = 0; + for (int i = 0; i < STATE_SIZE; i++) + { + uint64_t next = 0; + int pos = 0; + int largeSboxIndex = i; + for (int j = 0; j < SMALL_SBOX_COUNT / STATE_SIZE; j++) + { + next |= (uint64_t)sbox1[smallSboxIndex][(state[i] >> pos) & MASK1] << pos; + pos += SMALL_SBOX_WIDTH; + next |= (uint64_t)sbox2[largeSboxIndex][(state[i] >> pos) & MASK2] << pos; + pos += LARGE_SBOX_WIDTH; + smallSboxIndex++; + } + state[i] = next; + } +} + +void OdoCrypt::ApplyMaskedSwaps(uint64_t state[STATE_SIZE], const uint64_t mask[STATE_SIZE/2]) +{ + for (int i = 0; i < STATE_SIZE/2; i++) + { + uint64_t& a = state[2*i]; + uint64_t& b = state[2*i+1]; + // For each bit set in the mask, swap the corresponding bits in `a` and `b` + uint64_t swp = mask[i] & (a ^ b); + a ^= swp; + b ^= swp; + } +} + +void OdoCrypt::ApplyWordShuffle(uint64_t state[STATE_SIZE], int m) +{ + uint64_t next[STATE_SIZE]; + for (int i = 0; i < STATE_SIZE; i++) + { + next[m*i % STATE_SIZE] = state[i]; + } + std::copy(next, next+STATE_SIZE, state); +} + +inline uint64_t Rot(uint64_t x, int r) +{ + return r == 0 ? x : (x << r) ^ (x >> (64-r)); +} + +void OdoCrypt::ApplyPboxRotations(uint64_t state[STATE_SIZE], const int rotation[STATE_SIZE/2]) +{ + for (int i = 0; i < STATE_SIZE/2; i++) + { + // Only rotate the even words. Rotating the odd words wouldn't actually + // be useful - a transformation that rotates all the words can be + // transformed into one that only rotates the even words, then rotates + // the odd words once after the final iteration. + state[2*i] = Rot(state[2*i], rotation[i]); + } +} + +void OdoCrypt::ApplyPbox(uint64_t state[STATE_SIZE], const Pbox& perm) +{ + for (int i = 0; i < PBOX_SUBROUNDS-1; i++) + { + // Conditionally move bits between adjacent pairs of words + ApplyMaskedSwaps(state, perm.mask[i]); + // Move the words around + ApplyWordShuffle(state, PBOX_M); + // Rotate the bits within words + ApplyPboxRotations(state, perm.rotation[i]); + } + ApplyMaskedSwaps(state, perm.mask[PBOX_SUBROUNDS-1]); +} + +void OdoCrypt::ApplyInvPbox(uint64_t state[STATE_SIZE], const Pbox& perm) +{ + ApplyMaskedSwaps(state, perm.mask[PBOX_SUBROUNDS-1]); + for (int i = PBOX_SUBROUNDS-2; i >= 0; i--) + { + int invRotation[STATE_SIZE/2]; + for (int j = 0; j < STATE_SIZE/2; j++) + invRotation[j] = WORD_BITS - perm.rotation[i][j]; + ApplyPboxRotations(state, invRotation); + ApplyWordShuffle(state, INV_PBOX_M); + ApplyMaskedSwaps(state, perm.mask[i]); + } +} + +void OdoCrypt::ApplyRotations(uint64_t state[STATE_SIZE], const int rotations[ROTATION_COUNT]) +{ + uint64_t next[STATE_SIZE]; + std::rotate_copy(state, state+1, state+STATE_SIZE, next); + for (int i = 0; i < STATE_SIZE; i++) + for (int j = 0; j < ROTATION_COUNT; j++) + { + next[i] ^= Rot(state[i], rotations[j]); + } + std::copy(next, next+STATE_SIZE, state); +} + +void OdoCrypt::ApplyRoundKey(uint64_t state[STATE_SIZE], int roundKey) +{ + for (int i = 0; i < STATE_SIZE; i++) + state[i] ^= (roundKey >> i) & 1; +} diff --git a/src/Native/libmultihash/odocrypt.h b/src/Native/libmultihash/odocrypt.h new file mode 100644 index 000000000..11821c96d --- /dev/null +++ b/src/Native/libmultihash/odocrypt.h @@ -0,0 +1,97 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2018 The DigiByte developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef ODO_CRYPT +#define ODO_CRYPT + +#include + +class OdoCrypt +{ +public: + // Block size, in bytes + const static int DIGEST_SIZE = 80; + +private: + // Number of rounds. + const static int ROUNDS = 84; + // Odo utilizes two sbox sizes - 6-bit sboxes, which are ideally suited for + // FPGA logic elements, and 10-bit sboxes, which are ideally suited for FPGA + // RAM elements. + const static int SMALL_SBOX_WIDTH = 6; + const static int LARGE_SBOX_WIDTH = 10; + // The pboxes are constructed using 3 primitives, applied multiple times. + const static int PBOX_SUBROUNDS = 6; + // This constant should be a generator for the multiplicative group of + // integers modulo STATE_SIZE (3 or 7 for a STATE_SIZE of 10). It controls + // one part of the pbox step. + const static int PBOX_M = 3; + // The multiplicative inverse of PBOX_M modulo STATE_SIZE + const static int INV_PBOX_M = 7; + // This constant must be even. It controls the number of rotations used in + // the linear mixing step. + const static int ROTATION_COUNT = 6; + // Odo internally operates on 64-bit words. + const static int WORD_BITS = 64; + + const static int DIGEST_BITS = 8*DIGEST_SIZE; + const static int STATE_SIZE = DIGEST_BITS / WORD_BITS; + const static int SMALL_SBOX_COUNT = DIGEST_BITS / (SMALL_SBOX_WIDTH + LARGE_SBOX_WIDTH); + const static int LARGE_SBOX_COUNT = STATE_SIZE; + +public: + OdoCrypt(uint32_t key); + + void Encrypt(char cipher[DIGEST_SIZE], const char plain[DIGEST_SIZE]) const; + + // test-only, proves that this really is a permutation function + void Decrypt(char plain[DIGEST_SIZE], const char cipher[DIGEST_SIZE]) const; + +private: + struct Pbox + { + uint64_t mask[PBOX_SUBROUNDS][STATE_SIZE/2]; + int rotation[PBOX_SUBROUNDS-1][STATE_SIZE/2]; + }; + + uint8_t Sbox1[SMALL_SBOX_COUNT][1 << SMALL_SBOX_WIDTH]; + uint16_t Sbox2[LARGE_SBOX_COUNT][1 << LARGE_SBOX_WIDTH]; + Pbox Permutation[2]; + int Rotations[ROTATION_COUNT]; + uint16_t RoundKey[ROUNDS]; + + // Pack/unpack bytes into internal state + static void Unpack(uint64_t state[STATE_SIZE], const char bytes[DIGEST_SIZE]); + static void Pack(const uint64_t state[STATE_SIZE], char bytes[DIGEST_SIZE]); + + // Pre-mix the bits. Involution. After this step, 95% of the bits depend + // on a bit from the nonce. + static void PreMix(uint64_t state[STATE_SIZE]); + + // Non-linear substitution. + static void ApplySboxes( + uint64_t state[STATE_SIZE], + const uint8_t sbox1[SMALL_SBOX_COUNT][1 << SMALL_SBOX_WIDTH], + const uint16_t sbox2[LARGE_SBOX_COUNT][1 << LARGE_SBOX_WIDTH]); + + // ApplyPbox helpers + static void ApplyMaskedSwaps(uint64_t state[STATE_SIZE], const uint64_t mask[STATE_SIZE/2]); + static void ApplyWordShuffle(uint64_t state[STATE_SIZE], int m); + static void ApplyPboxRotations(uint64_t state[STATE_SIZE], const int rotation[STATE_SIZE/2]); + + // Permute the bits. + static void ApplyPbox(uint64_t state[STATE_SIZE], const Pbox& perm); + + // Inverse transform of ApplyPbox. Only used by Decrypt. + static void ApplyInvPbox(uint64_t state[STATE_SIZE], const Pbox& perm); + + // Linear mix step. + static void ApplyRotations(uint64_t state[STATE_SIZE], const int rotations[ROTATION_COUNT]); + + // Add round key. Involution. + static void ApplyRoundKey(uint64_t state[STATE_SIZE], int roundKey); +}; + +#endif From 37576c0f33541ca2d0c2aa7650c34c2237e76251 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 6 May 2019 16:26:01 +0200 Subject: [PATCH 141/178] Removed x22i support since SUQA is no more --- libs/runtimes/win-x64/libmultihash.dll | Bin 1211904 -> 1200640 bytes src/Miningcore.Tests/Crypto/HashingTests.cs | 11 -- .../Crypto/Hashing/Algorithms/X22i.cs | 42 ----- src/Miningcore/Native/LibMultihash.cs | 3 - src/Native/libmultihash/exports.cpp | 6 - src/Native/libmultihash/libmultihash.vcxproj | 2 - .../libmultihash/libmultihash.vcxproj.filters | 6 - src/Native/libmultihash/x22i.c | 144 ------------------ src/Native/libmultihash/x22i.h | 16 -- 9 files changed, 230 deletions(-) delete mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/X22i.cs delete mode 100644 src/Native/libmultihash/x22i.c delete mode 100644 src/Native/libmultihash/x22i.h diff --git a/libs/runtimes/win-x64/libmultihash.dll b/libs/runtimes/win-x64/libmultihash.dll index d87d8a69956e4f330d322aa88c412e09a73aa4b3..fac20143d4430f5d808e22618a6ffd4db5578045 100644 GIT binary patch delta 169691 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 WOeUht~Q2sxTm!79iz^o`3L=V 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 z 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 b$&8rP@ data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32, $"{nameof(result)} must be greater or equal 32 bytes"); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - LibMultihash.x22i(input, output, (uint) data.Length); - } - } - } - } -} diff --git a/src/Miningcore/Native/LibMultihash.cs b/src/Miningcore/Native/LibMultihash.cs index 8ae912618..81b20d948 100644 --- a/src/Miningcore/Native/LibMultihash.cs +++ b/src/Miningcore/Native/LibMultihash.cs @@ -46,9 +46,6 @@ public static unsafe class LibMultihash [DllImport("libmultihash", EntryPoint = "x17_export", CallingConvention = CallingConvention.Cdecl)] public static extern int x17(byte* input, void* output, uint inputLength); - [DllImport("libmultihash", EntryPoint = "x22i_export", CallingConvention = CallingConvention.Cdecl)] - public static extern int x22i(byte* input, void* output, uint inputLength); - [DllImport("libmultihash", EntryPoint = "x21s_export", CallingConvention = CallingConvention.Cdecl)] public static extern int x21s(byte* input, void* output, uint inputLength); diff --git a/src/Native/libmultihash/exports.cpp b/src/Native/libmultihash/exports.cpp index 8f2a328fd..2feac7b64 100644 --- a/src/Native/libmultihash/exports.cpp +++ b/src/Native/libmultihash/exports.cpp @@ -45,7 +45,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "Lyra2.h" #include "x16r.h" #include "x16s.h" -#include "x22i.h" #include "x21s.h" #include "hashodo.h" #include "equi/equihashverify.h" @@ -218,11 +217,6 @@ extern "C" MODULE_API void x16r_export(const char* input, char* output, uint32_t x16r_hash(input, output, input_len); } -extern "C" MODULE_API void x22i_export(const char* input, char* output, uint32_t input_len) -{ - x22i_hash(input, output, input_len); -} - extern "C" MODULE_API void x21s_export(const char* input, char* output, uint32_t input_len) { x21s_hash(input, output, input_len); diff --git a/src/Native/libmultihash/libmultihash.vcxproj b/src/Native/libmultihash/libmultihash.vcxproj index 585c78219..ffdd97e7c 100644 --- a/src/Native/libmultihash/libmultihash.vcxproj +++ b/src/Native/libmultihash/libmultihash.vcxproj @@ -262,7 +262,6 @@ - @@ -347,7 +346,6 @@ - diff --git a/src/Native/libmultihash/libmultihash.vcxproj.filters b/src/Native/libmultihash/libmultihash.vcxproj.filters index dedc78527..b008bae8f 100644 --- a/src/Native/libmultihash/libmultihash.vcxproj.filters +++ b/src/Native/libmultihash/libmultihash.vcxproj.filters @@ -275,9 +275,6 @@ Header Files - - Header Files - Header Files @@ -532,9 +529,6 @@ Source Files - - Source Files - Source Files diff --git a/src/Native/libmultihash/x22i.c b/src/Native/libmultihash/x22i.c deleted file mode 100644 index 21da3cfac..000000000 --- a/src/Native/libmultihash/x22i.c +++ /dev/null @@ -1,144 +0,0 @@ -#include -#include -#include - -#include "sha3/extra.h" -#include "sha3/sph_blake.h" -#include "sha3/sph_bmw.h" -#include "sha3/sph_groestl.h" -#include "sha3/sph_jh.h" -#include "sha3/sph_keccak.h" -#include "sha3/sph_skein.h" -#include "sha3/sph_luffa.h" -#include "sha3/sph_cubehash.h" -#include "sha3/sph_shavite.h" -#include "sha3/sph_simd.h" -#include "sha3/sph_echo.h" -#include "sha3/sph_hamsi.h" -#include "sha3/sph_fugue.h" -#include "sha3/sph_shabal.h" -#include "sha3/sph_whirlpool.h" -#include "sha3/sph_sha2.h" -#include "sha3/sph_haval.h" -#include "sha3/sph_tiger.h" -#include "Lyra2.h" -#include "sha3/gost_streebog.h" -#include "sha3/SWIFFTX.h" - -// barrystyle 05112018 - -void x22i_hash(const char* input, char* output, size_t input_len) -{ - unsigned char hash[64 * 4] = {0}, hash2[64] = {0}; - - sph_blake512_context ctx_blake; - sph_bmw512_context ctx_bmw; - sph_groestl512_context ctx_groestl; - sph_jh512_context ctx_jh; - sph_keccak512_context ctx_keccak; - sph_skein512_context ctx_skein; - sph_luffa512_context ctx_luffa; - sph_cubehash512_context ctx_cubehash; - sph_shavite512_context ctx_shavite; - sph_simd512_context ctx_simd; - sph_echo512_context ctx_echo; - sph_hamsi512_context ctx_hamsi; - sph_fugue512_context ctx_fugue; - sph_shabal512_context ctx_shabal; - sph_whirlpool_context ctx_whirlpool; - sph_sha512_context ctx_sha512; - sph_haval256_5_context ctx_haval; - sph_tiger_context ctx_tiger; - sph_gost512_context ctx_gost; - sph_sha256_context ctx_sha; - - sph_blake512_init(&ctx_blake); - sph_blake512(&ctx_blake, input, input_len); - sph_blake512_close(&ctx_blake, hash); - - sph_bmw512_init(&ctx_bmw); - sph_bmw512(&ctx_bmw, (const void*) hash, 64); - sph_bmw512_close(&ctx_bmw, hash); - - sph_groestl512_init(&ctx_groestl); - sph_groestl512(&ctx_groestl, (const void*) hash, 64); - sph_groestl512_close(&ctx_groestl, hash); - - sph_skein512_init(&ctx_skein); - sph_skein512(&ctx_skein, (const void*) hash, 64); - sph_skein512_close(&ctx_skein, hash); - - sph_jh512_init(&ctx_jh); - sph_jh512(&ctx_jh, (const void*) hash, 64); - sph_jh512_close(&ctx_jh, hash); - - sph_keccak512_init(&ctx_keccak); - sph_keccak512(&ctx_keccak, (const void*) hash, 64); - sph_keccak512_close(&ctx_keccak, hash); - - sph_luffa512_init(&ctx_luffa); - sph_luffa512(&ctx_luffa, (const void*) hash, 64); - sph_luffa512_close (&ctx_luffa, hash); - - sph_cubehash512_init(&ctx_cubehash); - sph_cubehash512(&ctx_cubehash, (const void*) hash, 64); - sph_cubehash512_close(&ctx_cubehash, hash); - - sph_shavite512_init(&ctx_shavite); - sph_shavite512(&ctx_shavite, (const void*) hash, 64); - sph_shavite512_close(&ctx_shavite, hash); - - sph_simd512_init(&ctx_simd); - sph_simd512(&ctx_simd, (const void*) hash, 64); - sph_simd512_close(&ctx_simd, hash); - - sph_echo512_init(&ctx_echo); - sph_echo512(&ctx_echo, (const void*) hash, 64); - sph_echo512_close(&ctx_echo, hash); - - sph_hamsi512_init(&ctx_hamsi); - sph_hamsi512(&ctx_hamsi, (const void*) hash, 64); - sph_hamsi512_close(&ctx_hamsi, hash); - - sph_fugue512_init(&ctx_fugue); - sph_fugue512(&ctx_fugue, (const void*) hash, 64); - sph_fugue512_close(&ctx_fugue, hash); - - sph_shabal512_init(&ctx_shabal); - sph_shabal512(&ctx_shabal, (const void*) hash, 64); - sph_shabal512_close(&ctx_shabal, &hash[64]); - - sph_whirlpool_init(&ctx_whirlpool); - sph_whirlpool (&ctx_whirlpool, (const void*) &hash[64], 64); - sph_whirlpool_close(&ctx_whirlpool, &hash[128]); - - sph_sha512_init(&ctx_sha512); - sph_sha512(&ctx_sha512,(const void*) &hash[128], 64); - sph_sha512_close(&ctx_sha512,(void*) &hash[192]); - - InitializeSWIFFTX(); - ComputeSingleSWIFFTX((unsigned char*)hash, (unsigned char*)hash2, false); - - memset(hash, 0, 64); - sph_haval256_5_init(&ctx_haval); - sph_haval256_5(&ctx_haval,(const void*) hash2, 64); - sph_haval256_5_close(&ctx_haval,hash); - - memset(hash2, 0, 64); - sph_tiger_init(&ctx_tiger); - sph_tiger (&ctx_tiger, (const void*) hash, 64); - sph_tiger_close(&ctx_tiger, (void*) hash2); - - memset(hash, 0, 64); - LYRA2((void*) hash, 32, (const void*) hash2, 32, (const void*) hash2, 32, 1, 4, 4); - - sph_gost512_init(&ctx_gost); - sph_gost512 (&ctx_gost, (const void*) hash, 64); - sph_gost512_close(&ctx_gost, (void*) hash); - - sph_sha256_init(&ctx_sha); - sph_sha256 (&ctx_sha, (const void*) hash, 64); - sph_sha256_close(&ctx_sha, (void*) hash); - - memcpy(output, hash, 32); -} diff --git a/src/Native/libmultihash/x22i.h b/src/Native/libmultihash/x22i.h deleted file mode 100644 index 6daaab143..000000000 --- a/src/Native/libmultihash/x22i.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef X22I_H -#define X22I_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -void x22i_hash(const char* input, char* output, size_t input_len); - -#ifdef __cplusplus -} -#endif - -#endif From fb4fd2b30f15cfd32b0bbb53bc7969942a23882a Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 6 May 2019 18:19:35 +0200 Subject: [PATCH 142/178] DGB-Odo --- src/Miningcore.Tests/Crypto/HashingTests.cs | 15 +- .../Blockchain/Bitcoin/BitcoinJob.cs | 4 +- .../Custom/BitcoinGold/BitcoinGoldJob.cs | 4 +- .../Blockchain/Equihash/EquihashJob.cs | 74 +- src/Miningcore/Configuration/ClusterConfig.cs | 26 +- .../Configuration/ClusterConfigExtensions.cs | 28 +- .../Crypto/Hashing/Algorithms/OdoCrypt.cs | 17 +- src/Miningcore/coins.json | 2488 +++++++++-------- 8 files changed, 1378 insertions(+), 1278 deletions(-) diff --git a/src/Miningcore.Tests/Crypto/HashingTests.cs b/src/Miningcore.Tests/Crypto/HashingTests.cs index b01034fb6..cc1b7f269 100644 --- a/src/Miningcore.Tests/Crypto/HashingTests.cs +++ b/src/Miningcore.Tests/Crypto/HashingTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using Miningcore.Crypto.Hashing.Algorithms; @@ -6,6 +7,7 @@ using Miningcore.Extensions; using Miningcore.Tests.Util; using Xunit; +using static Miningcore.Configuration.BitcoinTemplate; namespace Miningcore.Tests.Crypto { @@ -236,10 +238,19 @@ public void Odocrypt_Hash() { var hasher = new OdoCrypt(); var hash = new byte[32]; - hasher.Digest(testValue2, hash, 1u); + + var bnp = new BitcoinNetworkParams + { + Extra = new Dictionary + { + [nameof(OdoCryptConfig.OdoCryptShapeChangeInterval)] = 864000 + } + }; + + hasher.Digest(testValue2, hash, (ulong) 0x59ef86f2, null, null, bnp); var result = hash.ToHexString(); - Assert.Equal("0dcb8c6df9f2ee261668a3048b48ac39cf3ec9b07d10de886f50b962c0535768", result); + Assert.Equal("93164a82a79fba784dcf04c0b0f8537cc43821e7518bf513f296de50aefee4cf", result); } [Fact] diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs index ae298b3ca..68651db44 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs @@ -56,6 +56,7 @@ public class BitcoinJob protected IDestination poolAddressDestination; protected PoolConfig poolConfig; protected BitcoinTemplate coin; + private BitcoinTemplate.BitcoinNetworkParams networkParams; protected readonly HashSet submissions = new HashSet(); protected uint256 blockTargetValue; protected byte[] coinbaseFinal; @@ -347,7 +348,7 @@ protected virtual (Share Share, string BlockHex) ProcessShareInternal( // hash block-header var headerBytes = SerializeHeader(coinbaseHash, nTime, nonce, context.VersionRollingMask, versionBits); Span headerHash = stackalloc byte[32]; - headerHasher.Digest(headerBytes, headerHash, (ulong) nTime); + headerHasher.Digest(headerBytes, headerHash, (ulong) nTime, BlockTemplate, coin, networkParams); var headerValue = new uint256(headerHash); // calc share-diff @@ -556,6 +557,7 @@ public void Init(BlockTemplate blockTemplate, string jobId, this.poolConfig = poolConfig; coin = poolConfig.Template.As(); + networkParams = coin.GetNetwork(network.NetworkType); txVersion = coin.CoinbaseTxVersion; this.network = network; this.clock = clock; diff --git a/src/Miningcore/Blockchain/Equihash/Custom/BitcoinGold/BitcoinGoldJob.cs b/src/Miningcore/Blockchain/Equihash/Custom/BitcoinGold/BitcoinGoldJob.cs index a3c9df44a..0de021e40 100644 --- a/src/Miningcore/Blockchain/Equihash/Custom/BitcoinGold/BitcoinGoldJob.cs +++ b/src/Miningcore/Blockchain/Equihash/Custom/BitcoinGold/BitcoinGoldJob.cs @@ -175,10 +175,10 @@ public override void Init(EquihashBlockTemplate blockTemplate, string jobId, coin = poolConfig.Template.As(); this.network = network; var equihashTemplate = poolConfig.Template.As(); - chainConfig = coin.GetNetwork(network.NetworkType); + networkParams = coin.GetNetwork(network.NetworkType); BlockTemplate = blockTemplate; JobId = jobId; - Difficulty = (double) new BigRational(chainConfig.Diff1BValue, BlockTemplate.Target.HexToReverseByteArray().AsSpan().ToBigInteger()); + Difficulty = (double) new BigRational(networkParams.Diff1BValue, BlockTemplate.Target.HexToReverseByteArray().AsSpan().ToBigInteger()); this.solver = solver; diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJob.cs b/src/Miningcore/Blockchain/Equihash/EquihashJob.cs index a6c62a6ad..dba80155c 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJob.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJob.cs @@ -54,7 +54,7 @@ public class EquihashJob protected uint256 blockTargetValue; protected byte[] coinbaseInitial; - protected EquihashCoinTemplate.EquihashNetworkParams chainConfig; + protected EquihashCoinTemplate.EquihashNetworkParams networkParams; protected decimal blockReward; protected decimal rewardFees; @@ -88,7 +88,7 @@ public class EquihashJob protected virtual Transaction CreateOutputTransaction() { - var txNetwork = Network.GetNetwork(chainConfig.CoinbaseTxNetwork); + var txNetwork = Network.GetNetwork(networkParams.CoinbaseTxNetwork); var tx = Transaction.Create(txNetwork); // set versions @@ -101,33 +101,33 @@ protected virtual Transaction CreateOutputTransaction() } // calculate outputs - if(chainConfig.PayFoundersReward && - (chainConfig.LastFoundersRewardBlockHeight >= BlockTemplate.Height || - chainConfig.TreasuryRewardStartBlockHeight > 0)) + if(networkParams.PayFoundersReward && + (networkParams.LastFoundersRewardBlockHeight >= BlockTemplate.Height || + networkParams.TreasuryRewardStartBlockHeight > 0)) { // founders or treasury reward? - if(chainConfig.TreasuryRewardStartBlockHeight > 0 && - BlockTemplate.Height >= chainConfig.TreasuryRewardStartBlockHeight) + if(networkParams.TreasuryRewardStartBlockHeight > 0 && + BlockTemplate.Height >= networkParams.TreasuryRewardStartBlockHeight) { // pool reward (t-addr) - rewardToPool = new Money(Math.Round(blockReward * (1m - (chainConfig.PercentTreasuryReward) / 100m)) + rewardFees, MoneyUnit.Satoshi); + rewardToPool = new Money(Math.Round(blockReward * (1m - (networkParams.PercentTreasuryReward) / 100m)) + rewardFees, MoneyUnit.Satoshi); tx.Outputs.Add(rewardToPool, poolAddressDestination); // treasury reward (t-addr) var destination = FoundersAddressToScriptDestination(GetTreasuryRewardAddress()); - var amount = new Money(Math.Round(blockReward * (chainConfig.PercentTreasuryReward / 100m)), MoneyUnit.Satoshi); + var amount = new Money(Math.Round(blockReward * (networkParams.PercentTreasuryReward / 100m)), MoneyUnit.Satoshi); tx.Outputs.Add(amount, destination); } else { // pool reward (t-addr) - rewardToPool = new Money(Math.Round(blockReward * (1m - (chainConfig.PercentFoundersReward) / 100m)) + rewardFees, MoneyUnit.Satoshi); + rewardToPool = new Money(Math.Round(blockReward * (1m - (networkParams.PercentFoundersReward) / 100m)) + rewardFees, MoneyUnit.Satoshi); tx.Outputs.Add(rewardToPool, poolAddressDestination); // founders reward (t-addr) var destination = FoundersAddressToScriptDestination(GetFoundersRewardAddress()); - var amount = new Money(Math.Round(blockReward * (chainConfig.PercentFoundersReward / 100m)), MoneyUnit.Satoshi); + var amount = new Money(Math.Round(blockReward * (networkParams.PercentFoundersReward / 100m)), MoneyUnit.Satoshi); tx.Outputs.Add(amount, destination); } } @@ -145,10 +145,10 @@ protected virtual Transaction CreateOutputTransaction() private string GetTreasuryRewardAddress() { - var index = (int) Math.Floor((BlockTemplate.Height - chainConfig.TreasuryRewardStartBlockHeight) / - chainConfig.TreasuryRewardAddressChangeInterval % chainConfig.TreasuryRewardAddresses.Length); + var index = (int) Math.Floor((BlockTemplate.Height - networkParams.TreasuryRewardStartBlockHeight) / + networkParams.TreasuryRewardAddressChangeInterval % networkParams.TreasuryRewardAddresses.Length); - var address = chainConfig.TreasuryRewardAddresses[index]; + var address = networkParams.TreasuryRewardAddresses[index]; return address; } @@ -233,7 +233,7 @@ private byte[] SerializeBlock(Span header, Span coinbase, Span var headerBytes = SerializeHeader(nTime, nonce); // verify solution - if(!solver.Verify(headerBytes, solutionBytes.Slice(chainConfig.SolutionPreambleSize))) + if(!solver.Verify(headerBytes, solutionBytes.Slice(networkParams.SolutionPreambleSize))) throw new StratumException(StratumError.Other, "invalid solution"); // concat header and solution @@ -247,7 +247,7 @@ private byte[] SerializeBlock(Span header, Span coinbase, Span var headerValue = new uint256(headerHash); // calc share-diff - var shareDiff = (double) new BigRational(chainConfig.Diff1BValue, headerHash.ToBigInteger()); + var shareDiff = (double) new BigRational(networkParams.Diff1BValue, headerHash.ToBigInteger()); var stratumDifficulty = context.Difficulty; var ratio = shareDiff / stratumDifficulty; @@ -328,36 +328,36 @@ public virtual void Init(EquihashBlockTemplate blockTemplate, string jobId, this.clock = clock; this.poolAddressDestination = poolAddressDestination; coin = poolConfig.Template.As(); - chainConfig = coin.GetNetwork(network.NetworkType); + networkParams = coin.GetNetwork(network.NetworkType); this.network = network; BlockTemplate = blockTemplate; JobId = jobId; - Difficulty = (double) new BigRational(chainConfig.Diff1BValue, BlockTemplate.Target.HexToReverseByteArray().AsSpan().ToBigInteger()); + Difficulty = (double) new BigRational(networkParams.Diff1BValue, BlockTemplate.Target.HexToReverseByteArray().AsSpan().ToBigInteger()); // ZCash Sapling & Overwinter support - isSaplingActive = chainConfig.SaplingActivationHeight.HasValue && - chainConfig.SaplingTxVersion.HasValue && - chainConfig.SaplingTxVersionGroupId.HasValue && - chainConfig.SaplingActivationHeight.Value > 0 && - blockTemplate.Height >= chainConfig.SaplingActivationHeight.Value; + isSaplingActive = networkParams.SaplingActivationHeight.HasValue && + networkParams.SaplingTxVersion.HasValue && + networkParams.SaplingTxVersionGroupId.HasValue && + networkParams.SaplingActivationHeight.Value > 0 && + blockTemplate.Height >= networkParams.SaplingActivationHeight.Value; isOverwinterActive = isSaplingActive || - chainConfig.OverwinterTxVersion.HasValue && - chainConfig.OverwinterTxVersionGroupId.HasValue && - chainConfig.OverwinterActivationHeight.HasValue && - chainConfig.OverwinterActivationHeight.Value > 0 && - blockTemplate.Height >= chainConfig.OverwinterActivationHeight.Value; + networkParams.OverwinterTxVersion.HasValue && + networkParams.OverwinterTxVersionGroupId.HasValue && + networkParams.OverwinterActivationHeight.HasValue && + networkParams.OverwinterActivationHeight.Value > 0 && + blockTemplate.Height >= networkParams.OverwinterActivationHeight.Value; if(isSaplingActive) { - txVersion = chainConfig.SaplingTxVersion.Value; - txVersionGroupId = chainConfig.SaplingTxVersionGroupId.Value; + txVersion = networkParams.SaplingTxVersion.Value; + txVersionGroupId = networkParams.SaplingTxVersionGroupId.Value; } else if(isOverwinterActive) { - txVersion = chainConfig.OverwinterTxVersion.Value; - txVersionGroupId = chainConfig.OverwinterTxVersionGroupId.Value; + txVersion = networkParams.OverwinterTxVersion.Value; + txVersionGroupId = networkParams.OverwinterTxVersionGroupId.Value; } // Misc @@ -381,7 +381,7 @@ public virtual void Init(EquihashBlockTemplate blockTemplate, string jobId, else blockReward = BlockTemplate.CoinbaseValue; - if(chainConfig?.PayFoundersReward == true) + if(networkParams?.PayFoundersReward == true) { var founders = blockTemplate.Subsidy.Founders ?? blockTemplate.Subsidy.Community; @@ -451,7 +451,7 @@ public virtual void Init(EquihashBlockTemplate blockTemplate, string jobId, throw new StratumException(StratumError.Other, "incorrect size of extraNonce2"); // validate solution - if(solution.Length != (chainConfig.SolutionSize + chainConfig.SolutionPreambleSize) * 2) + if(solution.Length != (networkParams.SolutionSize + networkParams.SolutionPreambleSize) * 2) throw new StratumException(StratumError.Other, "incorrect size of solution"); // dupe check @@ -469,12 +469,12 @@ public object GetJobParams(bool isNew) public string GetFoundersRewardAddress() { - var maxHeight = chainConfig.LastFoundersRewardBlockHeight; + var maxHeight = networkParams.LastFoundersRewardBlockHeight; - var addressChangeInterval = (maxHeight + (ulong) chainConfig.FoundersRewardAddresses.Length) / (ulong) chainConfig.FoundersRewardAddresses.Length; + var addressChangeInterval = (maxHeight + (ulong) networkParams.FoundersRewardAddresses.Length) / (ulong) networkParams.FoundersRewardAddresses.Length; var index = BlockTemplate.Height / addressChangeInterval; - var address = chainConfig.FoundersRewardAddresses[index]; + var address = networkParams.FoundersRewardAddresses[index]; return address; } diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index 944f5034a..9d9226e32 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -92,6 +92,12 @@ public abstract partial class CoinTemplate /// public string ExplorerAccountLink { get; set; } + ///

+ /// Arbitrary extension data + /// + [JsonExtensionData] + public IDictionary Extra { get; set; } + /// /// Coin Family associciations /// @@ -116,6 +122,15 @@ public enum BitcoinSubfamily public partial class BitcoinTemplate : CoinTemplate { + public partial class BitcoinNetworkParams + { + /// + /// Arbitrary extension data + /// + [JsonExtensionData] + public IDictionary Extra { get; set; } + } + [JsonProperty(Order = -7, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] [DefaultValue(BitcoinSubfamily.None)] [JsonConverter(typeof(StringEnumConverter), true)] @@ -146,6 +161,9 @@ public partial class BitcoinTemplate : CoinTemplate [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] [DefaultValue(1.0d)] public double ShareMultiplier { get; set; } = 1.0d; + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public Dictionary Networks { get; set; } } public enum EquihashSubfamily @@ -377,6 +395,9 @@ public class DaemonEndpointConfig : AuthenticatedNetworkEndpointConfig /// public string HttpPath { get; set; } + /// + /// Arbitrary extension data + /// [JsonExtensionData] public IDictionary Extra { get; set; } } @@ -494,6 +515,9 @@ public partial class PoolPaymentProcessingConfig public PayoutScheme PayoutScheme { get; set; } public JToken PayoutSchemeConfig { get; set; } + /// + /// Arbitrary extension data + /// [JsonExtensionData] public IDictionary Extra { get; set; } } @@ -650,7 +674,7 @@ public partial class PoolConfig public bool? EnableInternalStratum { get; set; } /// - /// Extension data + /// Arbitrary extension data /// [JsonExtensionData] public IDictionary Extra { get; set; } diff --git a/src/Miningcore/Configuration/ClusterConfigExtensions.cs b/src/Miningcore/Configuration/ClusterConfigExtensions.cs index d1f419d39..52a6800be 100644 --- a/src/Miningcore/Configuration/ClusterConfigExtensions.cs +++ b/src/Miningcore/Configuration/ClusterConfigExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; using System.Numerics; using Autofac; @@ -75,7 +75,25 @@ public BitcoinTemplate() public IHashAlgorithm BlockHasherValue => blockHasherValue.Value; public IHashAlgorithm PoSBlockHasherValue => posBlockHasherValue.Value; - #region Overrides of CoinDefinition + public BitcoinNetworkParams GetNetwork(NetworkType networkType) + { + if(Networks == null || Networks.Count == 0) + return null; + + switch(networkType) + { + case NetworkType.Mainnet: + return Networks["main"]; + case NetworkType.Testnet: + return Networks["test"]; + case NetworkType.Regtest: + return Networks["regtest"]; + } + + throw new NotSupportedException("unsupported network type"); + } + + #region Overrides of CoinTemplate public override string GetAlgorithmName() { @@ -144,7 +162,7 @@ public EquihashNetworkParams GetNetwork(NetworkType networkType) throw new NotSupportedException("unsupported network type"); } - #region Overrides of CoinDefinition + #region Overrides of CoinTemplate public override string GetAlgorithmName() { @@ -157,7 +175,7 @@ public override string GetAlgorithmName() public partial class CryptonoteCoinTemplate { - #region Overrides of CoinDefinition + #region Overrides of CoinTemplate public override string GetAlgorithmName() { @@ -179,7 +197,7 @@ public override string GetAlgorithmName() public partial class EthereumCoinTemplate { - #region Overrides of CoinDefinition + #region Overrides of CoinTemplate public override string GetAlgorithmName() { diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/OdoCrypt.cs b/src/Miningcore/Crypto/Hashing/Algorithms/OdoCrypt.cs index 4cbf58a8a..9d7d77056 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/OdoCrypt.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/OdoCrypt.cs @@ -19,19 +19,34 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ using System; +using System.Runtime.CompilerServices; using Miningcore.Contracts; +using Miningcore.Extensions; using Miningcore.Native; +using static Miningcore.Configuration.BitcoinTemplate; namespace Miningcore.Crypto.Hashing.Algorithms { + public class OdoCryptConfig + { + public uint OdoCryptShapeChangeInterval { get; set; } + }; + public unsafe class OdoCrypt : IHashAlgorithm { + private static ConditionalWeakTable configs = new ConditionalWeakTable(); + public void Digest(ReadOnlySpan data, Span result, params object[] extra) { + Contract.Requires(extra.Length >= 4, $"{nameof(extra)} four extra parameters expected"); Contract.Requires(data.Length <= 80, $"{nameof(data)} must be less or equal 80 bytes"); Contract.Requires(result.Length >= 32, $"{nameof(result)} must be greater or equal 32 bytes"); - var key = (uint) extra[0]; + // derive key parameter + var nTime = (uint) (ulong) extra[0]; + var networkParams = (BitcoinNetworkParams) extra[3]; + var config = configs.GetValue(networkParams, (bnp) => bnp.Extra.SafeExtensionDataAs()); + var key = nTime - nTime % config.OdoCryptShapeChangeInterval; fixed (byte* input = data) { diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index 2139136a9..353c7ba42 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -1,1334 +1,1364 @@ { "bitcoin": { - "name": "Bitcoin", - "symbol": "BTC", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "explorerBlockLink": "https://blockchain.info/block/$height$", - "explorerTxLink": "https://blockchain.info/tx/{0}", - "explorerAccountLink": "https://blockchain.info/address/{0}" + "name": "Bitcoin", + "symbol": "BTC", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "sha256d" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "explorerBlockLink": "https://blockchain.info/block/$height$", + "explorerTxLink": "https://blockchain.info/tx/{0}", + "explorerAccountLink": "https://blockchain.info/address/{0}" }, "bitcoin-cash": { - "name": "Bitcoin Cash", - "symbol": "BCH", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "explorerBlockLink": "https://www.blocktrail.com/BCC/block/$height$", - "explorerTxLink": "https://www.blocktrail.com/BCC/tx/{0}", - "explorerAccountLink": "https://www.blocktrail.com/BCC/address/{0}" + "name": "Bitcoin Cash", + "symbol": "BCH", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "sha256d" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "explorerBlockLink": "https://www.blocktrail.com/BCC/block/$height$", + "explorerTxLink": "https://www.blocktrail.com/BCC/tx/{0}", + "explorerAccountLink": "https://www.blocktrail.com/BCC/address/{0}" }, "namecoin": { - "name": "Namecoin", - "symbol": "NMC", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "explorerBlockLink": "https://explorer.namecoin.info/b/$height$", - "explorerTxLink": "https://explorer.namecoin.info/tx/{0}", - "explorerAccountLink": "https://explorer.namecoin.info/a/{0}" + "name": "Namecoin", + "symbol": "NMC", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "sha256d" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "explorerBlockLink": "https://explorer.namecoin.info/b/$height$", + "explorerTxLink": "https://explorer.namecoin.info/tx/{0}", + "explorerAccountLink": "https://explorer.namecoin.info/a/{0}" }, "peercoin": { - "name": "Peercoin", - "symbol": "PPC", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "explorerBlockLink": "https://chainz.cryptoid.info/ppc/block.dws?$height$.htm", - "explorerTxLink": "https://chainz.cryptoid.info/ppc/tx.dws?{0}.htm", - "explorerAccountLink": "https://chainz.cryptoid.info/ppc/address.dws?{0}.htm" + "name": "Peercoin", + "symbol": "PPC", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "sha256d" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "explorerBlockLink": "https://chainz.cryptoid.info/ppc/block.dws?$height$.htm", + "explorerTxLink": "https://chainz.cryptoid.info/ppc/tx.dws?{0}.htm", + "explorerAccountLink": "https://chainz.cryptoid.info/ppc/address.dws?{0}.htm" }, "litecoin": { - "name": "Litecoin", - "symbol": "LTC", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "scrypt", - "args": [ 1024, 1 ] - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "posBlockHasher": { - "hash": "reverse", - "args": [ - { + "name": "Litecoin", + "symbol": "LTC", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { "hash": "scrypt", "args": [ 1024, 1 ] - } - ] - }, - "shareMultiplier": 65536, - "explorerBlockLink": "https://chainz.cryptoid.info/ltc/block.dws?$height$.htm", - "explorerTxLink": "https://chainz.cryptoid.info/ltc/tx.dws?{0}.htm", - "explorerAccountLink": "https://chainz.cryptoid.info/ltc/address.dws?{0}.htm" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "posBlockHasher": { + "hash": "reverse", + "args": [ + { + "hash": "scrypt", + "args": [ 1024, 1 ] + } + ] + }, + "shareMultiplier": 65536, + "explorerBlockLink": "https://chainz.cryptoid.info/ltc/block.dws?$height$.htm", + "explorerTxLink": "https://chainz.cryptoid.info/ltc/tx.dws?{0}.htm", + "explorerAccountLink": "https://chainz.cryptoid.info/ltc/address.dws?{0}.htm" }, "litecoin-cash": { - "name": "Litecoin Cash", - "symbol": "LCC", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "explorerBlockLink": "https://chainz.cryptoid.info/lcc/block.dws?$height$.htm", - "explorerTxLink": "https://chainz.cryptoid.info/lcc/tx.dws?{0}.htm", - "explorerAccountLink": "https://chainz.cryptoid.info/lcc/address.dws?{0}.htm" + "name": "Litecoin Cash", + "symbol": "LCC", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "sha256d" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "explorerBlockLink": "https://chainz.cryptoid.info/lcc/block.dws?$height$.htm", + "explorerTxLink": "https://chainz.cryptoid.info/lcc/tx.dws?{0}.htm", + "explorerAccountLink": "https://chainz.cryptoid.info/lcc/address.dws?{0}.htm" }, "dogecoin,": { - "name": "Dogecoin,", - "symbol": "DOGE", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "scrypt", - "args": [ 1024, 1 ] - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "posBlockHasher": { - "hash": "reverse", - "args": [ - { + "name": "Dogecoin,", + "symbol": "DOGE", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { "hash": "scrypt", "args": [ 1024, 1 ] - } - ] - }, - "shareMultiplier": 65536, - "explorerBlockLink": "https://dogechain.info/block/$height$", - "explorerTxLink": "https://dogechain.info/tx/{0}", - "explorerAccountLink": "https://dogechain.info/address/{0}" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "posBlockHasher": { + "hash": "reverse", + "args": [ + { + "hash": "scrypt", + "args": [ 1024, 1 ] + } + ] + }, + "shareMultiplier": 65536, + "explorerBlockLink": "https://dogechain.info/block/$height$", + "explorerTxLink": "https://dogechain.info/tx/{0}", + "explorerAccountLink": "https://dogechain.info/address/{0}" }, "viacoin": { - "name": "Viacoin", - "symbol": "VIA", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "scrypt", - "args": [ 1024, 1 ] - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "posBlockHasher": { - "hash": "reverse", - "args": [ - { + "name": "Viacoin", + "symbol": "VIA", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { "hash": "scrypt", "args": [ 1024, 1 ] - } - ] - }, - "shareMultiplier": 65536 + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "posBlockHasher": { + "hash": "reverse", + "args": [ + { + "hash": "scrypt", + "args": [ 1024, 1 ] + } + ] + }, + "shareMultiplier": 65536 }, "dash": { - "name": "Dash", - "symbol": "DASH", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "x11" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "x11" }] - }, - "hasMasterNodes": true, - "explorerBlockLink": "https://chainz.cryptoid.info/dash/block.dws?$height$.htm", - "explorerTxLink": "https://chainz.cryptoid.info/dash/tx.dws?{0}.htm", - "explorerAccountLink": "https://chainz.cryptoid.info/dash/address.dws?{0}.htm" + "name": "Dash", + "symbol": "DASH", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "x11" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "x11" } ] + }, + "hasMasterNodes": true, + "explorerBlockLink": "https://chainz.cryptoid.info/dash/block.dws?$height$.htm", + "explorerTxLink": "https://chainz.cryptoid.info/dash/tx.dws?{0}.htm", + "explorerAccountLink": "https://chainz.cryptoid.info/dash/address.dws?{0}.htm" }, "paccoin": { - "name": "Paccoin", - "symbol": "PAC", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "x11" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "x11" }] - }, - "hasMasterNodes": true, - "explorerBlockLink": "http://explorer.paccoin.net/block/$hash$", - "explorerTxLink": "http://explorer.paccoin.net/tx/{0}", - "explorerAccountLink": "http://explorer.paccoin.net/address/{0}" + "name": "Paccoin", + "symbol": "PAC", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "x11" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "x11" } ] + }, + "hasMasterNodes": true, + "explorerBlockLink": "http://explorer.paccoin.net/block/$hash$", + "explorerTxLink": "http://explorer.paccoin.net/tx/{0}", + "explorerAccountLink": "http://explorer.paccoin.net/address/{0}" }, "groestlcoin": { - "name": "GroestlCoin", - "symbol": "GRS", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256s" - }, - "headerHasher": { - "hash": "groestl" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "groestl" }] - }, - "shareMultiplier": 256, - "explorerBlockLink": "https://groestlsight.groestlcoin.org/block/$height$", - "explorerTxLink": "https://groestlsight.groestlcoin.org/tx/{0}", - "explorerAccountLink": "https://groestlsight.groestlcoin.org/address/{0}" + "name": "GroestlCoin", + "symbol": "GRS", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256s" + }, + "headerHasher": { + "hash": "groestl" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "groestl" } ] + }, + "shareMultiplier": 256, + "explorerBlockLink": "https://groestlsight.groestlcoin.org/block/$height$", + "explorerTxLink": "https://groestlsight.groestlcoin.org/tx/{0}", + "explorerAccountLink": "https://groestlsight.groestlcoin.org/address/{0}" }, "monacoin": { - "name": "Monacoin", - "symbol": "MONA", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "lyra2rev2" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "shareMultiplier": 256, - "explorerBlockLink": "https://bchain.info/MONA/block/$height$", - "explorerTxLink": "https://bchain.info/MONA/tx/{0}", - "explorerAccountLink": "https://bchain.info/MONA/addr/{0}" + "name": "Monacoin", + "symbol": "MONA", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "lyra2rev2" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "shareMultiplier": 256, + "explorerBlockLink": "https://bchain.info/MONA/block/$height$", + "explorerTxLink": "https://bchain.info/MONA/tx/{0}", + "explorerAccountLink": "https://bchain.info/MONA/addr/{0}" }, "vertcoin": { - "name": "Vertcoin", - "symbol": "VTC", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "lyra2rev3" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "shareMultiplier": 256, - "explorerBlockLink": "https://chainz.cryptoid.info/vtc/block.dws?$height$.htm", - "explorerTxLink": "https://chainz.cryptoid.info/vtc/tx.dws?{0}.htm", - "explorerAccountLink": "https://chainz.cryptoid.info/vtc/address.dws?{0}.htm" + "name": "Vertcoin", + "symbol": "VTC", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "lyra2rev3" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "shareMultiplier": 256, + "explorerBlockLink": "https://chainz.cryptoid.info/vtc/block.dws?$height$.htm", + "explorerTxLink": "https://chainz.cryptoid.info/vtc/tx.dws?{0}.htm", + "explorerAccountLink": "https://chainz.cryptoid.info/vtc/address.dws?{0}.htm" }, "globaltoken": { - "name": "Globaltoken", - "symbol": "GLT", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "explorerBlockLink": "https://bchain.info/GLT/block/$height$", - "explorerTxLink": "https://bchain.info/GLT/tx/{0}", - "explorerAccountLink": "https://bchain.info/GLT/addr/{0}" + "name": "Globaltoken", + "symbol": "GLT", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "sha256d" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "explorerBlockLink": "https://bchain.info/GLT/block/$height$", + "explorerTxLink": "https://bchain.info/GLT/tx/{0}", + "explorerAccountLink": "https://bchain.info/GLT/addr/{0}" }, "mooncoin": { - "name": "MoonCoin", - "symbol": "MOON", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "scrypt", - "args": [ 1024, 1 ] - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "posBlockHasher": { - "hash": "reverse", - "args": [ - { + "name": "MoonCoin", + "symbol": "MOON", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { "hash": "scrypt", "args": [ 1024, 1 ] - } - ] - }, - "shareMultiplier": 65536, - "explorerBlockLink": "https://chainz.cryptoid.info/moon/block.dws?$height$.htm", - "explorerTxLink": "https://chainz.cryptoid.info/moon/tx.dws?{0}.htm", - "explorerAccountLink": "https://chainz.cryptoid.info/moon/address.dws?{0}.htm" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "posBlockHasher": { + "hash": "reverse", + "args": [ + { + "hash": "scrypt", + "args": [ 1024, 1 ] + } + ] + }, + "shareMultiplier": 65536, + "explorerBlockLink": "https://chainz.cryptoid.info/moon/block.dws?$height$.htm", + "explorerTxLink": "https://chainz.cryptoid.info/moon/tx.dws?{0}.htm", + "explorerAccountLink": "https://chainz.cryptoid.info/moon/address.dws?{0}.htm" }, "pakcoin": { - "name": "PAKcoin", - "symbol": "PAK", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "scrypt", - "args": [ 1024, 1 ] - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "posBlockHasher": { - "hash": "reverse", - "args": [ - { + "name": "PAKcoin", + "symbol": "PAK", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { "hash": "scrypt", "args": [ 1024, 1 ] - } - ] - }, - "shareMultiplier": 65536, - "explorerBlockLink": "https://chainz.cryptoid.info/pak/block.dws?$height$.htm", - "explorerTxLink": "https://chainz.cryptoid.info/pak/tx.dws?{0}.htm", - "explorerAccountLink": "https://chainz.cryptoid.info/pak/address.dws?{0}.htm" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "posBlockHasher": { + "hash": "reverse", + "args": [ + { + "hash": "scrypt", + "args": [ 1024, 1 ] + } + ] + }, + "shareMultiplier": 65536, + "explorerBlockLink": "https://chainz.cryptoid.info/pak/block.dws?$height$.htm", + "explorerTxLink": "https://chainz.cryptoid.info/pak/tx.dws?{0}.htm", + "explorerAccountLink": "https://chainz.cryptoid.info/pak/address.dws?{0}.htm" }, "cannabiscoin": { - "name": "CannabisCoin", - "symbol": "CANN", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "x11" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "x11" }] - }, - "explorerBlockLink": "https://chainz.cryptoid.info/cann/block.dws?$height$.htm", - "explorerTxLink": "https://chainz.cryptoid.info/cann/tx.dws?{0}.htm", - "explorerAccountLink": "https://chainz.cryptoid.info/cann/address.dws?{0}.htm" + "name": "CannabisCoin", + "symbol": "CANN", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "x11" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "x11" } ] + }, + "explorerBlockLink": "https://chainz.cryptoid.info/cann/block.dws?$height$.htm", + "explorerTxLink": "https://chainz.cryptoid.info/cann/tx.dws?{0}.htm", + "explorerAccountLink": "https://chainz.cryptoid.info/cann/address.dws?{0}.htm" }, "ravencoin": { - "name": "Ravencoin", - "symbol": "RVN", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "x16r" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "x16r" }] - }, - "shareMultiplier": 256, - "explorerBlockLink": "https://ravencoin.network/block/$hash$", - "explorerTxLink": "https://ravencoin.network/tx/{0}", - "explorerAccountLink": "https://ravencoin.network/address/{0}" + "name": "Ravencoin", + "symbol": "RVN", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "x16r" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "x16r" } ] + }, + "shareMultiplier": 256, + "explorerBlockLink": "https://ravencoin.network/block/$hash$", + "explorerTxLink": "https://ravencoin.network/tx/{0}", + "explorerAccountLink": "https://ravencoin.network/address/{0}" }, "pigeoncoin": { - "name": "Pigeoncoin", - "symbol": "PGN", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "x16s" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "x16s" }] - }, - "shareMultiplier": 256, - "explorerBlockLink": "http://explorer.pigeoncoin.org/block/$hash$", - "explorerTxLink": "http://explorer.pigeoncoin.org/tx/{0}", - "explorerAccountLink": "http://explorer.pigeoncoin.org/address/{0}" + "name": "Pigeoncoin", + "symbol": "PGN", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "x16s" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "x16s" } ] + }, + "shareMultiplier": 256, + "explorerBlockLink": "http://explorer.pigeoncoin.org/block/$hash$", + "explorerTxLink": "http://explorer.pigeoncoin.org/tx/{0}", + "explorerAccountLink": "http://explorer.pigeoncoin.org/address/{0}" }, "bitcoin-diamond": { - "name": "Bitcoin Diamond", - "symbol": "BCD", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "x13bcd" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "explorerBlockLink": "http://explorer.btcd.io/#/blockInfo?hash=$hash$", - "explorerTxLink": "http://explorer.btcd.io/#/TX?TX={0}", - "explorerAccountLink": "http://explorer.btcd.io/#/address?address={0}" + "name": "Bitcoin Diamond", + "symbol": "BCD", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "x13bcd" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "explorerBlockLink": "http://explorer.btcd.io/#/blockInfo?hash=$hash$", + "explorerTxLink": "http://explorer.btcd.io/#/TX?TX={0}", + "explorerAccountLink": "http://explorer.btcd.io/#/address?address={0}" }, "flo": { - "name": "FLO", - "symbol": "FLO", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "scrypt", - "args": [ 1024, 1 ] - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "posBlockHasher": { - "hash": "reverse", - "args": [ - { + "name": "FLO", + "symbol": "FLO", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { "hash": "scrypt", "args": [ 1024, 1 ] - } - ] - }, - "coinbaseTxVersion": 2, - "coinbaseTxComment": "FLO Miningcore", - "shareMultiplier": 65536, - "explorerBlockLink": "http://network.flo.cash/block/$hash$", - "explorerTxLink": "http://network.flo.cash/tx/{0}", - "explorerAccountLink": "http://network.flo.cash/address/{0}" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "posBlockHasher": { + "hash": "reverse", + "args": [ + { + "hash": "scrypt", + "args": [ 1024, 1 ] + } + ] + }, + "coinbaseTxVersion": 2, + "coinbaseTxComment": "FLO Miningcore", + "shareMultiplier": 65536, + "explorerBlockLink": "http://network.flo.cash/block/$hash$", + "explorerTxLink": "http://network.flo.cash/tx/{0}", + "explorerAccountLink": "http://network.flo.cash/address/{0}" }, "digibyte-sha256": { - "name": "Digibyte-Sha256", - "symbol": "DGB", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "explorerBlockLink": "https://digiexplorer.info/block/$height$", - "explorerTxLink": "https://digiexplorer.info/tx/{0}", - "explorerAccountLink": "https://digiexplorer.info/address/{0}" + "name": "Digibyte-Sha256", + "symbol": "DGB", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "sha256d" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "explorerBlockLink": "https://digiexplorer.info/block/$height$", + "explorerTxLink": "https://digiexplorer.info/tx/{0}", + "explorerAccountLink": "https://digiexplorer.info/address/{0}" }, "digibyte-scrypt": { - "name": "Digibyte-Scrypt", - "symbol": "DGB", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "scrypt", - "args": [ 1024, 1 ] - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "shareMultiplier": 65536, - "explorerBlockLink": "https://digiexplorer.info/block/$height$", - "explorerTxLink": "https://digiexplorer.info/tx/{0}", - "explorerAccountLink": "https://digiexplorer.info/address/{0}" + "name": "Digibyte-Scrypt", + "symbol": "DGB", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "scrypt", + "args": [ 1024, 1 ] + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "shareMultiplier": 65536, + "explorerBlockLink": "https://digiexplorer.info/block/$height$", + "explorerTxLink": "https://digiexplorer.info/tx/{0}", + "explorerAccountLink": "https://digiexplorer.info/address/{0}" }, "digibyte-skein": { - "name": "Digibyte-Skein", - "symbol": "DGB", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "skein" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "explorerBlockLink": "https://digiexplorer.info/block/$height$", - "explorerTxLink": "https://digiexplorer.info/tx/{0}", - "explorerAccountLink": "https://digiexplorer.info/address/{0}" + "name": "Digibyte-Skein", + "symbol": "DGB", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "skein" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "explorerBlockLink": "https://digiexplorer.info/block/$height$", + "explorerTxLink": "https://digiexplorer.info/tx/{0}", + "explorerAccountLink": "https://digiexplorer.info/address/{0}" }, "digibyte-qubit": { - "name": "Digibyte-Qubit", - "symbol": "DGB", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "qubit" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "explorerBlockLink": "https://digiexplorer.info/block/$height$", - "explorerTxLink": "https://digiexplorer.info/tx/{0}", - "explorerAccountLink": "https://digiexplorer.info/address/{0}" + "name": "Digibyte-Qubit", + "symbol": "DGB", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "qubit" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "explorerBlockLink": "https://digiexplorer.info/block/$height$", + "explorerTxLink": "https://digiexplorer.info/tx/{0}", + "explorerAccountLink": "https://digiexplorer.info/address/{0}" }, "digibyte-groestl": { - "name": "Digibyte-Groestl", - "symbol": "DGB", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256s" - }, - "headerHasher": { - "hash": "groestlmyriad" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "sha256d" }] - }, - "shareMultiplier": 256, - "explorerBlockLink": "https://digiexplorer.info/block/$height$", - "explorerTxLink": "https://digiexplorer.info/tx/{0}", - "explorerAccountLink": "https://digiexplorer.info/address/{0}" + "name": "Digibyte-Groestl", + "symbol": "DGB", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256s" + }, + "headerHasher": { + "hash": "groestlmyriad" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "shareMultiplier": 256, + "explorerBlockLink": "https://digiexplorer.info/block/$height$", + "explorerTxLink": "https://digiexplorer.info/tx/{0}", + "explorerAccountLink": "https://digiexplorer.info/address/{0}" + }, + "digibyte-odo": { + "name": "Digibyte-Odo", + "symbol": "DGB", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256s" + }, + "headerHasher": { + "hash": "odocrypt" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "sha256d" } ] + }, + "networks": { + "main": { + "odoCryptShapeChangeInterval": 864000 + }, + "test": { + "odoCryptShapeChangeInterval": 86400 + }, + "regtest": { + "odoCryptShapeChangeInterval": 60 + } + }, + "shareMultiplier": 256, + "explorerBlockLink": "https://digiexplorer.info/block/$height$", + "explorerTxLink": "https://digiexplorer.info/tx/{0}", + "explorerAccountLink": "https://digiexplorer.info/address/{0}" }, "verge-lyra": { - "name": "Verge-Lyra", - "symbol": "XVG", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "lyra2rev2" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "scrypt", - "args": [ 1024, 1 ] - } - ] - }, - "shareMultiplier": 256, - "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", - "explorerTxLink": "https://verge-blockchain.info/tx/{0}", - "explorerAccountLink": "https://verge-blockchain.info/address/{0}" + "name": "Verge-Lyra", + "symbol": "XVG", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "lyra2rev2" + }, + "blockHasher": { + "hash": "reverse", + "args": [ + { + "hash": "scrypt", + "args": [ 1024, 1 ] + } + ] + }, + "shareMultiplier": 256, + "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", + "explorerTxLink": "https://verge-blockchain.info/tx/{0}", + "explorerAccountLink": "https://verge-blockchain.info/address/{0}" }, "verge-scrypt": { - "name": "Verge-Scrypt", - "symbol": "XVG", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "scrypt", - "args": [ 1024, 1 ] - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { + "name": "Verge-Scrypt", + "symbol": "XVG", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { "hash": "scrypt", "args": [ 1024, 1 ] - } - ] - }, - "shareMultiplier": 65536, - "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", - "explorerTxLink": "https://verge-blockchain.info/tx/{0}", - "explorerAccountLink": "https://verge-blockchain.info/address/{0}" + }, + "blockHasher": { + "hash": "reverse", + "args": [ + { + "hash": "scrypt", + "args": [ 1024, 1 ] + } + ] + }, + "shareMultiplier": 65536, + "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", + "explorerTxLink": "https://verge-blockchain.info/tx/{0}", + "explorerAccountLink": "https://verge-blockchain.info/address/{0}" }, "verge-x17": { - "name": "Verge-X17", - "symbol": "XVG", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "x17" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "scrypt", - "args": [ 1024, 1 ] - } - ] - }, - "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", - "explorerTxLink": "https://verge-blockchain.info/tx/{0}", - "explorerAccountLink": "https://verge-blockchain.info/address/{0}" + "name": "Verge-X17", + "symbol": "XVG", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "x17" + }, + "blockHasher": { + "hash": "reverse", + "args": [ + { + "hash": "scrypt", + "args": [ 1024, 1 ] + } + ] + }, + "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", + "explorerTxLink": "https://verge-blockchain.info/tx/{0}", + "explorerAccountLink": "https://verge-blockchain.info/address/{0}" }, "verge-blake": { - "name": "Verge-Blake", - "symbol": "XVG", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "blake2s" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "scrypt", - "args": [ 1024, 1 ] - } - ] - }, - "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", - "explorerTxLink": "https://verge-blockchain.info/tx/{0}", - "explorerAccountLink": "https://verge-blockchain.info/address/{0}" + "name": "Verge-Blake", + "symbol": "XVG", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "blake2s" + }, + "blockHasher": { + "hash": "reverse", + "args": [ + { + "hash": "scrypt", + "args": [ 1024, 1 ] + } + ] + }, + "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", + "explorerTxLink": "https://verge-blockchain.info/tx/{0}", + "explorerAccountLink": "https://verge-blockchain.info/address/{0}" }, "verge-groestl": { - "name": "Verge-Groestl", - "symbol": "XVG", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "groestlmyriad" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "scrypt", - "args": [ 1024, 1 ] - } - ] - }, - "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", - "explorerTxLink": "https://verge-blockchain.info/tx/{0}", - "explorerAccountLink": "https://verge-blockchain.info/address/{0}" + "name": "Verge-Groestl", + "symbol": "XVG", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "groestlmyriad" + }, + "blockHasher": { + "hash": "reverse", + "args": [ + { + "hash": "scrypt", + "args": [ 1024, 1 ] + } + ] + }, + "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", + "explorerTxLink": "https://verge-blockchain.info/tx/{0}", + "explorerAccountLink": "https://verge-blockchain.info/address/{0}" }, "geekcash": { - "name": "GeekCash", - "symbol": "GEEK", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "geek" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "geek" }] - }, - "hasMasterNodes": true, - "explorerBlockLink": "http://explorer.geekcash.org/block/$hash$", - "explorerTxLink": "http://explorer.geekcash.org/tx/{0}", - "explorerAccountLink": "http://explorer.geekcash.org/address/{0}" + "name": "GeekCash", + "symbol": "GEEK", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "geek" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "geek" } ] + }, + "hasMasterNodes": true, + "explorerBlockLink": "http://explorer.geekcash.org/block/$hash$", + "explorerTxLink": "http://explorer.geekcash.org/tx/{0}", + "explorerAccountLink": "http://explorer.geekcash.org/address/{0}" }, "help-the-homeless": { - "name": "Help The Homeless", - "symbol": "HTH", - "family": "bitcoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "x16r" - }, - "blockHasher": { - "hash": "reverse", - "args": [{ "hash": "x16r" }] - }, - "shareMultiplier": 256, - "hasMasterNodes": true, - "explorerBlockLink": "http://explorer.hthcoin.world/block/$hash$", - "explorerTxLink": "http://explorer.hthcoin.world/tx/{0}", - "explorerAccountLink": "http://explorer.hthcoin.world/address/{0}" + "name": "Help The Homeless", + "symbol": "HTH", + "family": "bitcoin", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "x16r" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "x16r" } ] + }, + "shareMultiplier": 256, + "hasMasterNodes": true, + "explorerBlockLink": "http://explorer.hthcoin.world/block/$hash$", + "explorerTxLink": "http://explorer.hthcoin.world/tx/{0}", + "explorerAccountLink": "http://explorer.hthcoin.world/address/{0}" }, "zcash": { - "name": "ZCash", - "symbol": "ZEC", - "family": "equihash", - "networks": { - "main": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 1344, - "solutionPreambleSize": 3, - "solver": { - "hash": "equihash", - "args": [ 200, 9, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "zcash-main", - "payFoundersReward": true, - "percentFoundersReward": 20, - "foundersRewardAddresses": [ - "t3Vz22vK5z2LcKEdg16Yv4FFneEL1zg9ojd", - "t3cL9AucCajm3HXDhb5jBnJK2vapVoXsop3", - "t3fqvkzrrNaMcamkQMwAyHRjfDdM2xQvDTR", - "t3TgZ9ZT2CTSK44AnUPi6qeNaHa2eC7pUyF", - "t3SpkcPQPfuRYHsP5vz3Pv86PgKo5m9KVmx", - "t3Xt4oQMRPagwbpQqkgAViQgtST4VoSWR6S", - "t3ayBkZ4w6kKXynwoHZFUSSgXRKtogTXNgb", - "t3adJBQuaa21u7NxbR8YMzp3km3TbSZ4MGB", - "t3K4aLYagSSBySdrfAGGeUd5H9z5Qvz88t2", - "t3RYnsc5nhEvKiva3ZPhfRSk7eyh1CrA6Rk", - "t3Ut4KUq2ZSMTPNE67pBU5LqYCi2q36KpXQ", - "t3ZnCNAvgu6CSyHm1vWtrx3aiN98dSAGpnD", - "t3fB9cB3eSYim64BS9xfwAHQUKLgQQroBDG", - "t3cwZfKNNj2vXMAHBQeewm6pXhKFdhk18kD", - "t3YcoujXfspWy7rbNUsGKxFEWZqNstGpeG4", - "t3bLvCLigc6rbNrUTS5NwkgyVrZcZumTRa4", - "t3VvHWa7r3oy67YtU4LZKGCWa2J6eGHvShi", - "t3eF9X6X2dSo7MCvTjfZEzwWrVzquxRLNeY", - "t3esCNwwmcyc8i9qQfyTbYhTqmYXZ9AwK3X", - "t3M4jN7hYE2e27yLsuQPPjuVek81WV3VbBj", - "t3gGWxdC67CYNoBbPjNvrrWLAWxPqZLxrVY", - "t3LTWeoxeWPbmdkUD3NWBquk4WkazhFBmvU", - "t3P5KKX97gXYFSaSjJPiruQEX84yF5z3Tjq", - "t3f3T3nCWsEpzmD35VK62JgQfFig74dV8C9", - "t3Rqonuzz7afkF7156ZA4vi4iimRSEn41hj", - "t3fJZ5jYsyxDtvNrWBeoMbvJaQCj4JJgbgX", - "t3Pnbg7XjP7FGPBUuz75H65aczphHgkpoJW", - "t3WeKQDxCijL5X7rwFem1MTL9ZwVJkUFhpF", - "t3Y9FNi26J7UtAUC4moaETLbMo8KS1Be6ME", - "t3aNRLLsL2y8xcjPheZZwFy3Pcv7CsTwBec", - "t3gQDEavk5VzAAHK8TrQu2BWDLxEiF1unBm", - "t3Rbykhx1TUFrgXrmBYrAJe2STxRKFL7G9r", - "t3aaW4aTdP7a8d1VTE1Bod2yhbeggHgMajR", - "t3YEiAa6uEjXwFL2v5ztU1fn3yKgzMQqNyo", - "t3g1yUUwt2PbmDvMDevTCPWUcbDatL2iQGP", - "t3dPWnep6YqGPuY1CecgbeZrY9iUwH8Yd4z", - "t3QRZXHDPh2hwU46iQs2776kRuuWfwFp4dV", - "t3enhACRxi1ZD7e8ePomVGKn7wp7N9fFJ3r", - "t3PkLgT71TnF112nSwBToXsD77yNbx2gJJY", - "t3LQtHUDoe7ZhhvddRv4vnaoNAhCr2f4oFN", - "t3fNcdBUbycvbCtsD2n9q3LuxG7jVPvFB8L", - "t3dKojUU2EMjs28nHV84TvkVEUDu1M1FaEx", - "t3aKH6NiWN1ofGd8c19rZiqgYpkJ3n679ME", - "t3MEXDF9Wsi63KwpPuQdD6by32Mw2bNTbEa", - "t3WDhPfik343yNmPTqtkZAoQZeqA83K7Y3f", - "t3PSn5TbMMAEw7Eu36DYctFezRzpX1hzf3M", - "t3R3Y5vnBLrEn8L6wFjPjBLnxSUQsKnmFpv", - "t3Pcm737EsVkGTbhsu2NekKtJeG92mvYyoN" - ], - "foundersRewardSubsidySlowStartInterval": 20000, - "foundersRewardSubsidyHalvingInterval": 840000, - "overwinterActivationHeight": 347500, - "overwinterTxVersion": 3, - "overwinterTxVersionGroupId": 63210096, - "saplingActivationHeight": 419200, - "saplingTxVersion": 4, - "saplingTxVersionGroupId": 2301567109 - }, - "test": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 1344, - "solutionPreambleSize": 3, - "solver": { - "hash": "equihash", - "args": [ 200, 9, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "zcash-test", - "payFoundersReward": true, - "percentFoundersReward": 20, - "foundersRewardAddresses": [ - "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi", - "t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543", - "t2NGQjYMQhFndDHguvUw4wZdNdsssA6K7x2", - "t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy", - "t2BkYdVCHzvTJJUTx4yZB8qeegD8QsPx8bo", - "t2J8q1xH1EuigJ52MfExyyjYtN3VgvshKDf", - "t2Crq9mydTm37kZokC68HzT6yez3t2FBnFj", - "t2EaMPUiQ1kthqcP5UEkF42CAFKJqXCkXC9", - "t2F9dtQc63JDDyrhnfpzvVYTJcr57MkqA12", - "t2LPirmnfYSZc481GgZBa6xUGcoovfytBnC", - "t26xfxoSw2UV9Pe5o3C8V4YybQD4SESfxtp", - "t2D3k4fNdErd66YxtvXEdft9xuLoKD7CcVo", - "t2DWYBkxKNivdmsMiivNJzutaQGqmoRjRnL", - "t2C3kFF9iQRxfc4B9zgbWo4dQLLqzqjpuGQ", - "t2MnT5tzu9HSKcppRyUNwoTp8MUueuSGNaB", - "t2AREsWdoW1F8EQYsScsjkgqobmgrkKeUkK", - "t2Vf4wKcJ3ZFtLj4jezUUKkwYR92BLHn5UT", - "t2K3fdViH6R5tRuXLphKyoYXyZhyWGghDNY", - "t2VEn3KiKyHSGyzd3nDw6ESWtaCQHwuv9WC", - "t2F8XouqdNMq6zzEvxQXHV1TjwZRHwRg8gC", - "t2BS7Mrbaef3fA4xrmkvDisFVXVrRBnZ6Qj", - "t2FuSwoLCdBVPwdZuYoHrEzxAb9qy4qjbnL", - "t2SX3U8NtrT6gz5Db1AtQCSGjrpptr8JC6h", - "t2V51gZNSoJ5kRL74bf9YTtbZuv8Fcqx2FH", - "t2FyTsLjjdm4jeVwir4xzj7FAkUidbr1b4R", - "t2EYbGLekmpqHyn8UBF6kqpahrYm7D6N1Le", - "t2NQTrStZHtJECNFT3dUBLYA9AErxPCmkka", - "t2GSWZZJzoesYxfPTWXkFn5UaxjiYxGBU2a", - "t2RpffkzyLRevGM3w9aWdqMX6bd8uuAK3vn", - "t2JzjoQqnuXtTGSN7k7yk5keURBGvYofh1d", - "t2AEefc72ieTnsXKmgK2bZNckiwvZe3oPNL", - "t2NNs3ZGZFsNj2wvmVd8BSwSfvETgiLrD8J", - "t2ECCQPVcxUCSSQopdNquguEPE14HsVfcUn", - "t2JabDUkG8TaqVKYfqDJ3rqkVdHKp6hwXvG", - "t2FGzW5Zdc8Cy98ZKmRygsVGi6oKcmYir9n", - "t2DUD8a21FtEFn42oVLp5NGbogY13uyjy9t", - "t2UjVSd3zheHPgAkuX8WQW2CiC9xHQ8EvWp", - "t2TBUAhELyHUn8i6SXYsXz5Lmy7kDzA1uT5", - "t2Tz3uCyhP6eizUWDc3bGH7XUC9GQsEyQNc", - "t2NysJSZtLwMLWEJ6MH3BsxRh6h27mNcsSy", - "t2KXJVVyyrjVxxSeazbY9ksGyft4qsXUNm9", - "t2J9YYtH31cveiLZzjaE4AcuwVho6qjTNzp", - "t2QgvW4sP9zaGpPMH1GRzy7cpydmuRfB4AZ", - "t2NDTJP9MosKpyFPHJmfjc5pGCvAU58XGa4", - "t29pHDBWq7qN4EjwSEHg8wEqYe9pkmVrtRP", - "t2Ez9KM8VJLuArcxuEkNRAkhNvidKkzXcjJ", - "t2D5y7J5fpXajLbGrMBQkFg2mFN8fo3n8cX", - "t2UV2wr1PTaUiybpkV3FdSdGxUJeZdZztyt" - ], - "foundersRewardSubsidySlowStartInterval": 20000, - "foundersRewardSubsidyHalvingInterval": 840000, - "overwinterActivationHeight": 207500, - "overwinterTxVersion": 3, - "overwinterTxVersionGroupId": 63210096, - "saplingActivationHeight": 280000, - "saplingTxVersion": 4, - "saplingTxVersionGroupId": 2301567109 - }, - "regtest": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 1344, - "solutionPreambleSize": 3, - "solver": { - "hash": "equihash", - "args": [ 200, 9, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "zcash-reg", - "payFoundersReward": true, - "percentFoundersReward": 20, - "foundersRewardAddresses": [ "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" ], - "foundersRewardSubsidyHalvingInterval": 150 - } - }, - "usesZCashAddressFormat": true, - "useBitcoinPayoutHandler": false, - "explorerBlockLink": "https://explorer.zcha.in/blocks/$hash$", - "explorerTxLink": "https://explorer.zcha.in/transactions/{0}", - "explorerAccountLink": "https://explorer.zcha.in/accounts/{0}" + "name": "ZCash", + "symbol": "ZEC", + "family": "equihash", + "networks": { + "main": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 1344, + "solutionPreambleSize": 3, + "solver": { + "hash": "equihash", + "args": [ 200, 9, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "zcash-main", + "payFoundersReward": true, + "percentFoundersReward": 20, + "foundersRewardAddresses": [ + "t3Vz22vK5z2LcKEdg16Yv4FFneEL1zg9ojd", + "t3cL9AucCajm3HXDhb5jBnJK2vapVoXsop3", + "t3fqvkzrrNaMcamkQMwAyHRjfDdM2xQvDTR", + "t3TgZ9ZT2CTSK44AnUPi6qeNaHa2eC7pUyF", + "t3SpkcPQPfuRYHsP5vz3Pv86PgKo5m9KVmx", + "t3Xt4oQMRPagwbpQqkgAViQgtST4VoSWR6S", + "t3ayBkZ4w6kKXynwoHZFUSSgXRKtogTXNgb", + "t3adJBQuaa21u7NxbR8YMzp3km3TbSZ4MGB", + "t3K4aLYagSSBySdrfAGGeUd5H9z5Qvz88t2", + "t3RYnsc5nhEvKiva3ZPhfRSk7eyh1CrA6Rk", + "t3Ut4KUq2ZSMTPNE67pBU5LqYCi2q36KpXQ", + "t3ZnCNAvgu6CSyHm1vWtrx3aiN98dSAGpnD", + "t3fB9cB3eSYim64BS9xfwAHQUKLgQQroBDG", + "t3cwZfKNNj2vXMAHBQeewm6pXhKFdhk18kD", + "t3YcoujXfspWy7rbNUsGKxFEWZqNstGpeG4", + "t3bLvCLigc6rbNrUTS5NwkgyVrZcZumTRa4", + "t3VvHWa7r3oy67YtU4LZKGCWa2J6eGHvShi", + "t3eF9X6X2dSo7MCvTjfZEzwWrVzquxRLNeY", + "t3esCNwwmcyc8i9qQfyTbYhTqmYXZ9AwK3X", + "t3M4jN7hYE2e27yLsuQPPjuVek81WV3VbBj", + "t3gGWxdC67CYNoBbPjNvrrWLAWxPqZLxrVY", + "t3LTWeoxeWPbmdkUD3NWBquk4WkazhFBmvU", + "t3P5KKX97gXYFSaSjJPiruQEX84yF5z3Tjq", + "t3f3T3nCWsEpzmD35VK62JgQfFig74dV8C9", + "t3Rqonuzz7afkF7156ZA4vi4iimRSEn41hj", + "t3fJZ5jYsyxDtvNrWBeoMbvJaQCj4JJgbgX", + "t3Pnbg7XjP7FGPBUuz75H65aczphHgkpoJW", + "t3WeKQDxCijL5X7rwFem1MTL9ZwVJkUFhpF", + "t3Y9FNi26J7UtAUC4moaETLbMo8KS1Be6ME", + "t3aNRLLsL2y8xcjPheZZwFy3Pcv7CsTwBec", + "t3gQDEavk5VzAAHK8TrQu2BWDLxEiF1unBm", + "t3Rbykhx1TUFrgXrmBYrAJe2STxRKFL7G9r", + "t3aaW4aTdP7a8d1VTE1Bod2yhbeggHgMajR", + "t3YEiAa6uEjXwFL2v5ztU1fn3yKgzMQqNyo", + "t3g1yUUwt2PbmDvMDevTCPWUcbDatL2iQGP", + "t3dPWnep6YqGPuY1CecgbeZrY9iUwH8Yd4z", + "t3QRZXHDPh2hwU46iQs2776kRuuWfwFp4dV", + "t3enhACRxi1ZD7e8ePomVGKn7wp7N9fFJ3r", + "t3PkLgT71TnF112nSwBToXsD77yNbx2gJJY", + "t3LQtHUDoe7ZhhvddRv4vnaoNAhCr2f4oFN", + "t3fNcdBUbycvbCtsD2n9q3LuxG7jVPvFB8L", + "t3dKojUU2EMjs28nHV84TvkVEUDu1M1FaEx", + "t3aKH6NiWN1ofGd8c19rZiqgYpkJ3n679ME", + "t3MEXDF9Wsi63KwpPuQdD6by32Mw2bNTbEa", + "t3WDhPfik343yNmPTqtkZAoQZeqA83K7Y3f", + "t3PSn5TbMMAEw7Eu36DYctFezRzpX1hzf3M", + "t3R3Y5vnBLrEn8L6wFjPjBLnxSUQsKnmFpv", + "t3Pcm737EsVkGTbhsu2NekKtJeG92mvYyoN" + ], + "foundersRewardSubsidySlowStartInterval": 20000, + "foundersRewardSubsidyHalvingInterval": 840000, + "overwinterActivationHeight": 347500, + "overwinterTxVersion": 3, + "overwinterTxVersionGroupId": 63210096, + "saplingActivationHeight": 419200, + "saplingTxVersion": 4, + "saplingTxVersionGroupId": 2301567109 + }, + "test": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 1344, + "solutionPreambleSize": 3, + "solver": { + "hash": "equihash", + "args": [ 200, 9, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "zcash-test", + "payFoundersReward": true, + "percentFoundersReward": 20, + "foundersRewardAddresses": [ + "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi", + "t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543", + "t2NGQjYMQhFndDHguvUw4wZdNdsssA6K7x2", + "t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy", + "t2BkYdVCHzvTJJUTx4yZB8qeegD8QsPx8bo", + "t2J8q1xH1EuigJ52MfExyyjYtN3VgvshKDf", + "t2Crq9mydTm37kZokC68HzT6yez3t2FBnFj", + "t2EaMPUiQ1kthqcP5UEkF42CAFKJqXCkXC9", + "t2F9dtQc63JDDyrhnfpzvVYTJcr57MkqA12", + "t2LPirmnfYSZc481GgZBa6xUGcoovfytBnC", + "t26xfxoSw2UV9Pe5o3C8V4YybQD4SESfxtp", + "t2D3k4fNdErd66YxtvXEdft9xuLoKD7CcVo", + "t2DWYBkxKNivdmsMiivNJzutaQGqmoRjRnL", + "t2C3kFF9iQRxfc4B9zgbWo4dQLLqzqjpuGQ", + "t2MnT5tzu9HSKcppRyUNwoTp8MUueuSGNaB", + "t2AREsWdoW1F8EQYsScsjkgqobmgrkKeUkK", + "t2Vf4wKcJ3ZFtLj4jezUUKkwYR92BLHn5UT", + "t2K3fdViH6R5tRuXLphKyoYXyZhyWGghDNY", + "t2VEn3KiKyHSGyzd3nDw6ESWtaCQHwuv9WC", + "t2F8XouqdNMq6zzEvxQXHV1TjwZRHwRg8gC", + "t2BS7Mrbaef3fA4xrmkvDisFVXVrRBnZ6Qj", + "t2FuSwoLCdBVPwdZuYoHrEzxAb9qy4qjbnL", + "t2SX3U8NtrT6gz5Db1AtQCSGjrpptr8JC6h", + "t2V51gZNSoJ5kRL74bf9YTtbZuv8Fcqx2FH", + "t2FyTsLjjdm4jeVwir4xzj7FAkUidbr1b4R", + "t2EYbGLekmpqHyn8UBF6kqpahrYm7D6N1Le", + "t2NQTrStZHtJECNFT3dUBLYA9AErxPCmkka", + "t2GSWZZJzoesYxfPTWXkFn5UaxjiYxGBU2a", + "t2RpffkzyLRevGM3w9aWdqMX6bd8uuAK3vn", + "t2JzjoQqnuXtTGSN7k7yk5keURBGvYofh1d", + "t2AEefc72ieTnsXKmgK2bZNckiwvZe3oPNL", + "t2NNs3ZGZFsNj2wvmVd8BSwSfvETgiLrD8J", + "t2ECCQPVcxUCSSQopdNquguEPE14HsVfcUn", + "t2JabDUkG8TaqVKYfqDJ3rqkVdHKp6hwXvG", + "t2FGzW5Zdc8Cy98ZKmRygsVGi6oKcmYir9n", + "t2DUD8a21FtEFn42oVLp5NGbogY13uyjy9t", + "t2UjVSd3zheHPgAkuX8WQW2CiC9xHQ8EvWp", + "t2TBUAhELyHUn8i6SXYsXz5Lmy7kDzA1uT5", + "t2Tz3uCyhP6eizUWDc3bGH7XUC9GQsEyQNc", + "t2NysJSZtLwMLWEJ6MH3BsxRh6h27mNcsSy", + "t2KXJVVyyrjVxxSeazbY9ksGyft4qsXUNm9", + "t2J9YYtH31cveiLZzjaE4AcuwVho6qjTNzp", + "t2QgvW4sP9zaGpPMH1GRzy7cpydmuRfB4AZ", + "t2NDTJP9MosKpyFPHJmfjc5pGCvAU58XGa4", + "t29pHDBWq7qN4EjwSEHg8wEqYe9pkmVrtRP", + "t2Ez9KM8VJLuArcxuEkNRAkhNvidKkzXcjJ", + "t2D5y7J5fpXajLbGrMBQkFg2mFN8fo3n8cX", + "t2UV2wr1PTaUiybpkV3FdSdGxUJeZdZztyt" + ], + "foundersRewardSubsidySlowStartInterval": 20000, + "foundersRewardSubsidyHalvingInterval": 840000, + "overwinterActivationHeight": 207500, + "overwinterTxVersion": 3, + "overwinterTxVersionGroupId": 63210096, + "saplingActivationHeight": 280000, + "saplingTxVersion": 4, + "saplingTxVersionGroupId": 2301567109 + }, + "regtest": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 1344, + "solutionPreambleSize": 3, + "solver": { + "hash": "equihash", + "args": [ 200, 9, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "zcash-reg", + "payFoundersReward": true, + "percentFoundersReward": 20, + "foundersRewardAddresses": [ "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" ], + "foundersRewardSubsidyHalvingInterval": 150 + } + }, + "usesZCashAddressFormat": true, + "useBitcoinPayoutHandler": false, + "explorerBlockLink": "https://explorer.zcha.in/blocks/$hash$", + "explorerTxLink": "https://explorer.zcha.in/transactions/{0}", + "explorerAccountLink": "https://explorer.zcha.in/accounts/{0}" }, "zclassic": { - "name": "ZClassic", - "symbol": "ZCL", - "family": "equihash", - "networks": { - "main": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 1344, - "solutionPreambleSize": 3, - "solver": { - "hash": "equihash", - "args": [ 200, 9, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "main", - "payFoundersReward": false - }, - "test": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 1344, - "solutionPreambleSize": 3, - "solver": { - "hash": "equihash", - "args": [ 200, 9, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "testnet", - "payFoundersReward": false - }, - "regtest": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 1344, - "solutionPreambleSize": 3, - "solver": { - "hash": "equihash", - "args": [ 200, 9, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "regtest", - "payFoundersReward": false - } - }, - "usesZCashAddressFormat": true, - "useBitcoinPayoutHandler": false, - "explorerBlockLink": "http://explorer.zclmine.pro/block/$height$", - "explorerTxLink": "http://explorer.zclmine.pro/transactions/{0}", - "explorerAccountLink": "http://explorer.zclmine.pro/accounts/{0}" + "name": "ZClassic", + "symbol": "ZCL", + "family": "equihash", + "networks": { + "main": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 1344, + "solutionPreambleSize": 3, + "solver": { + "hash": "equihash", + "args": [ 200, 9, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "main", + "payFoundersReward": false + }, + "test": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 1344, + "solutionPreambleSize": 3, + "solver": { + "hash": "equihash", + "args": [ 200, 9, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "testnet", + "payFoundersReward": false + }, + "regtest": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 1344, + "solutionPreambleSize": 3, + "solver": { + "hash": "equihash", + "args": [ 200, 9, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "regtest", + "payFoundersReward": false + } + }, + "usesZCashAddressFormat": true, + "useBitcoinPayoutHandler": false, + "explorerBlockLink": "http://explorer.zclmine.pro/block/$height$", + "explorerTxLink": "http://explorer.zclmine.pro/transactions/{0}", + "explorerAccountLink": "http://explorer.zclmine.pro/accounts/{0}" }, "zencash": { - "name": "Zencash", - "symbol": "ZEN", - "family": "equihash", - "networks": { - "main": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 1344, - "solutionPreambleSize": 3, - "solver": { - "hash": "equihash", - "args": [ 200, 9, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "main", - "payFoundersReward": true, - "percentFoundersReward": 8.5, - "foundersRewardAddresses": [ - "zssEdGnZCQ9G86LZFtbynMn1hYTVhn6eYCL", - "zsrCsXXmUf8k59NLasEKfxA7us3iNvaPATz", - "zsnLPsWMXW2s4w9EmFSwtSLRxL2LhPcfdby", - "zshdovbcPfUAfkPeEE2qLbKnoue9RsbVokU", - "zsqmq97JAKCCBFRGvxgv6FiJgQLCZBDp62S", - "zskyFVFA7VRYX8EGdXmYN75WaBB25FmiL3g", - "zsmncLmwEUdVmAGPUrUnNKmPGXyej7mbmdM", - "zsfa9VVJCEdjfPbku4XrFcRR8kTDm2T64rz", - "zsjdMnfWuFi46VeN2HSXVQWEGsnGHgVxayY", - "zseb8wRQ8rZ722oLX5B8rx7qwZiBRb9mdig", - "zsjxkovhqiMVggoW7jvSRi3NTSD3a6b6qfd", - "zsokCCSU3wvZrS2G6mEDpJ5cH49E7sDyNr1", - "zt12EsFgkABHLMRXA7JNnpMqLrxsgCLnVEV", - "zt39mvuG9gDTHX8A8Qk45rbk3dSdQoJ8ZAv", - "zssTQZs5YxDGijKC86dvcDxzWogWcK7n5AK", - "zsywuMoQK7Bved2nrXs56AEtWBhpb88rMzS", - "zsxVS2w7h1fHFX2nQtGm4372pd4DSHzq9ee", - "zsupGi7ro3uC8CEVwm9r7vrdVUZaXQnHF6T", - "zshVZvW47dA5AB3Sqk1h7ytwWJeUJUJxxaE", - "zsubBCjvDx252MKFsL4Dcf5rJU9Z9Upqr1N", - "zsweaST3NcU4hfgkVULfCsfEq41pjgMDgcW", - "zswz6Rxb1S33fUpftETZwtGiVSeYxNKq2xc", - "zswnpHtiBbrvYDzbhPQshkgvLSfYhDMRJ4S", - "zsjSYAWaEYj35Ht7aXrRJUGY6Dc8qCmgYqu", - "zsvMv8fGroWR8epbSiGDCJHmfe6ec2uFQrt", - "zsujxCT56BExQDAwKwktBjtnopYnw8BiKbg", - "zsxeXc2FTAzmUmeZmqVsKVdwTMSvzyns4rT", - "zsuLqgABNudD8bVPbVGeUjGqapuoXp68i7F", - "zsoc39J1dCFK1U8kckZznvQkv8As7sajYLz", - "zt21NFdu1KRPJ7VRKtrWugM2Jqe5ePNmU4T", - "zsp15qbVcbx9ifcjKe6XZEJTvzsFUZ2BHLT", - "zso2KvqH6yxLQEYggHdmfL3Tcd5V6E9tqhp", - "zsnFG2W5ZHRYh3QucNze4mp31tBkemtfxdj", - "zsex2CGJtxHyHbpLXm7kESBmp3vWRqUkJMy", - "zsvtFv96nrgrXKUbtNe2BpCt8aQEp5oJ7F8", - "zsk5KitThmhK9KBa1KDybPgEmGSFTHzhMVA", - "zsuy4n48c4NsJyaCZEzwdAKULM1FqbB6Y4z", - "zsgtQVMpX2zNMLvHHG2NDwfqKoaebvVectJ", - "zszQqXRSPGdqsWw4iaMTNN6aJz4JjEzSdCF", - "zst6dBLrTtaMQBX7BLMNjKLTGcP11PBmgTV", - "zshD9r6Eb6dZGdzYW2HCb9CzkMokCT1NGJR", - "zswUaj1TboEGmvSfF7fdoxWyH3RMx7MBHHo", - "zsv8s4Poi5GxCsbBrRJ97Vsvazp84nrz5AN", - "zsmmxrKU6dqWFwUKow1iyovg3gxrgXpEivr", - "zskh1221aRC9WEfb5a59WxffeW34McmZZsw", - "zssAhuj57NnVm4yNFT6o8muRctABkUaBu3L", - "zsi5Yr4Z8HwBvdBqQE8gk7ahExDu95J4oqZ", - "zsy6ryEaxfk8emJ8bGVB7tmwRwBL8cfSqBW" - ], - "foundersRewardSubsidySlowStartInterval": 2, - "foundersRewardSubsidyHalvingInterval": 840000, - "percentTreasuryReward": 12, - "treasuryRewardStartBlockHeight": 139200, - "treasuryRewardAddresses": [ - "zsyF68hcYYNLPj5i4PfQJ1kUY6nsFnZkc82", - "zsfULrmbX7xbhqhAFRffVqCw9RyGv2hqNNG", - "zsoemTfqjicem2QVU8cgBHquKb1o9JR5p4Z", - "zt339oiGL6tTgc9Q71f5g1sFTZf6QiXrRUr" - ], - "treasuryRewardAddressChangeInterval": 50000 - }, - "test": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 1344, - "solutionPreambleSize": 3, - "solver": { - "hash": "equihash", - "args": [ 200, 9, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "testnet", - "payFoundersReward": true, - "percentFoundersReward": 8.5, - "foundersRewardAddresses": [ - "zrH8KT8KUcpKKNBu3fjH4hA84jZBCawErqn", - "zrGsMC4ou1r5Vxy7Dnxg4PfKpansx83BM8g", - "zr6sB2Az36D8CqzeZNavB11WbovsGtJSAZG", - "zrBAG3pXCTDq14nivNK9mW8SfwMNcdmMQpb", - "zrRLwpYRYky4wsvwLVrDp8fs89EBTRhNMB1", - "zrLozMfptTmE3zLP5SrTLyB8TXqH84Agjrr", - "zrMckkaLtVTEUvxj4ouU7BPDGa8xmdTZSVE", - "zrFc897wJXmF7BcEdbvi2mS1bLrcuWYK6hm", - "zrHEnni486u9SNcLWacroSgcdyMA33tfM92", - "zrJ3ymPV3R8Xk4N3BdNb898xvZvARm5K7mq", - "zrDj3P6trx73291krxU51U9QnfkbGxkyJ6E", - "zrJs3vMGFJi9pQCireeSLckJonamBnwTSrY", - "zrKFdXQoAkkycy52EFoWARyzZWx6Kat2Som", - "zrEXbSe79FXA9KRMnJTZUWZdZhNnjcnAdrq", - "zr7iAwfNgJsMpSCmijK3TuVDuNvSmLr1rUz", - "zrDEK7K6cftqSjeyVUH1WqJtBUkXN7GidxH", - "zrRennuq75hyBVU4JymtZk8UcQ1vRPKpmpj", - "zr9HRTL79pKmn5R8fvkC9kucZ4u1bQruLTD", - "zrML8KXpJsa1NVnbJuawX86ZvAn543tWdTT", - "zrLBAkQoxpEtnztSUEcdxnEvuwtgxyAMGX7", - "zr6kPnVzFBYmcBDsWoTrPHRuBxLq21o4zvT", - "zrMY3vdvqs9KSvx9TawvcyuVurt1Jj6GPVo", - "zr9WB1qBpM4nwi1mudUFfjtMNmqzaBQDsXn", - "zrAHbtHDPAqmzWJMQqSYzGyFnDWN3oELZRs", - "zrH1f5K3z7EQ6RWWZ7StCDWHTZwFChBVA2W", - "zrNTacAid9LS4kAqzM4sw1YcF7gLFrzVM7U", - "zrFyZpMVKMeDqbn6A2uUiL9mZmgxuR1pUBg", - "zrD1cqGFGzBcPogFHJvnN4XegvvmbTjA43t", - "zr5A1D7czWkB4pAWfGC5Pux5Ek7anYybdPK", - "zr8yTAxCy6jAdsc6qPvmVEQHbYo25AJKhy9", - "zrFW2YjQw4cABim5kEDwapbSqTz3wW7cWkk", - "zr9nJvNbsrvUTZD41fhqAQeUcgMfqZmAweN", - "zrCx4dXZd5b2tD483Ds4diHpo1QxBMJ76Jr", - "zr6eVeRwU6Puob3K1RfWtva1R458oj8pzkL", - "zr7B92iHtQcobZjGCXo3DAqMQjsn7ka31wE", - "zr8bcemLWAjYuphXSVqtqZWEnJipCB9F5oC", - "zrFzsuPXb7HsFd3srBqtVqnC9GQ94DQubV2", - "zr4yiBobiHjHnCYi75NmYtyoqCV4A3kpHDL", - "zrGVdR4K4F8MfmWxhUiTypK7PTsvHi8uTAh", - "zr7WiCDqCMvUdH1xmMu8YrBMFb2x2E6BX3z", - "zrEFrGWLX4hPHuHRUD3TPbMAJyeSpMSctUc", - "zr5c3f8PTnW8qBFX1GvK2LhyLBBCb1WDdGG", - "zrGkAZkZLqC9QKJR3XomgxNizCpNuAupTeg", - "zrM7muDowiun9tCHhu5K9vcDGfUptuYorfZ", - "zrCsWfwKotWnQmFviqAHAPAJ2jXqZYW966P", - "zrLLB3JB3jozUoMGFEGhjqyVXTpngVQ8c4T", - "zrAEa8YjJ2f3m2VsM1Xa9EwibZxEnRoSLUx", - "zrAdJgp7Cx35xTvB7ABWP8YLTNDArMjP1s3" - ], - "foundersRewardSubsidySlowStartInterval": 2, - "foundersRewardSubsidyHalvingInterval": 840000, - "percentTreasuryReward": 12, - "treasuryRewardStartBlockHeight": 85500, - "treasuryRewardAddresses": [ - "zrRBQ5heytPMN5nY3ssPf3cG4jocXeD8fm1", - "zrRBQ5heytPMN5nY3ssPf3cG4jocXeD8fm1", - "zrRBQ5heytPMN5nY3ssPf3cG4jocXeD8fm1", - "zrRBQ5heytPMN5nY3ssPf3cG4jocXeD8fm1" - ], - "treasuryRewardAddressChangeInterval": 10000 - }, - "regtest": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 1344, - "solutionPreambleSize": 3, - "solver": { - "hash": "equihash", - "args": [ 200, 9, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "regtest", - "payFoundersReward": true, - "percentFoundersReward": 8.5, - "foundersRewardAddresses": [ "zrKmSdqZKZjnARd5e8FfRg4v1m74X7twxGa" ], - "foundersRewardSubsidyHalvingInterval": 2000, - "percentTreasuryReward": 12, - "treasuryRewardStartBlockHeight": 139200, - "treasuryRewardAddresses": [ "zrKmSdqZKZjnARd5e8FfRg4v1m74X7twxGa" ], - "treasuryRewardAddressChangeInterval": 100 - } - }, - "usesZCashAddressFormat": true, - "useBitcoinPayoutHandler": false, - "explorerBlockLink": "http://explorer.zensystem.io/block/$hash$", - "explorerTxLink": "http://explorer.zensystem.io/transactions/{0}", - "explorerAccountLink": "http://explorer.zensystem.io/accounts/{0}" + "name": "Zencash", + "symbol": "ZEN", + "family": "equihash", + "networks": { + "main": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 1344, + "solutionPreambleSize": 3, + "solver": { + "hash": "equihash", + "args": [ 200, 9, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "main", + "payFoundersReward": true, + "percentFoundersReward": 8.5, + "foundersRewardAddresses": [ + "zssEdGnZCQ9G86LZFtbynMn1hYTVhn6eYCL", + "zsrCsXXmUf8k59NLasEKfxA7us3iNvaPATz", + "zsnLPsWMXW2s4w9EmFSwtSLRxL2LhPcfdby", + "zshdovbcPfUAfkPeEE2qLbKnoue9RsbVokU", + "zsqmq97JAKCCBFRGvxgv6FiJgQLCZBDp62S", + "zskyFVFA7VRYX8EGdXmYN75WaBB25FmiL3g", + "zsmncLmwEUdVmAGPUrUnNKmPGXyej7mbmdM", + "zsfa9VVJCEdjfPbku4XrFcRR8kTDm2T64rz", + "zsjdMnfWuFi46VeN2HSXVQWEGsnGHgVxayY", + "zseb8wRQ8rZ722oLX5B8rx7qwZiBRb9mdig", + "zsjxkovhqiMVggoW7jvSRi3NTSD3a6b6qfd", + "zsokCCSU3wvZrS2G6mEDpJ5cH49E7sDyNr1", + "zt12EsFgkABHLMRXA7JNnpMqLrxsgCLnVEV", + "zt39mvuG9gDTHX8A8Qk45rbk3dSdQoJ8ZAv", + "zssTQZs5YxDGijKC86dvcDxzWogWcK7n5AK", + "zsywuMoQK7Bved2nrXs56AEtWBhpb88rMzS", + "zsxVS2w7h1fHFX2nQtGm4372pd4DSHzq9ee", + "zsupGi7ro3uC8CEVwm9r7vrdVUZaXQnHF6T", + "zshVZvW47dA5AB3Sqk1h7ytwWJeUJUJxxaE", + "zsubBCjvDx252MKFsL4Dcf5rJU9Z9Upqr1N", + "zsweaST3NcU4hfgkVULfCsfEq41pjgMDgcW", + "zswz6Rxb1S33fUpftETZwtGiVSeYxNKq2xc", + "zswnpHtiBbrvYDzbhPQshkgvLSfYhDMRJ4S", + "zsjSYAWaEYj35Ht7aXrRJUGY6Dc8qCmgYqu", + "zsvMv8fGroWR8epbSiGDCJHmfe6ec2uFQrt", + "zsujxCT56BExQDAwKwktBjtnopYnw8BiKbg", + "zsxeXc2FTAzmUmeZmqVsKVdwTMSvzyns4rT", + "zsuLqgABNudD8bVPbVGeUjGqapuoXp68i7F", + "zsoc39J1dCFK1U8kckZznvQkv8As7sajYLz", + "zt21NFdu1KRPJ7VRKtrWugM2Jqe5ePNmU4T", + "zsp15qbVcbx9ifcjKe6XZEJTvzsFUZ2BHLT", + "zso2KvqH6yxLQEYggHdmfL3Tcd5V6E9tqhp", + "zsnFG2W5ZHRYh3QucNze4mp31tBkemtfxdj", + "zsex2CGJtxHyHbpLXm7kESBmp3vWRqUkJMy", + "zsvtFv96nrgrXKUbtNe2BpCt8aQEp5oJ7F8", + "zsk5KitThmhK9KBa1KDybPgEmGSFTHzhMVA", + "zsuy4n48c4NsJyaCZEzwdAKULM1FqbB6Y4z", + "zsgtQVMpX2zNMLvHHG2NDwfqKoaebvVectJ", + "zszQqXRSPGdqsWw4iaMTNN6aJz4JjEzSdCF", + "zst6dBLrTtaMQBX7BLMNjKLTGcP11PBmgTV", + "zshD9r6Eb6dZGdzYW2HCb9CzkMokCT1NGJR", + "zswUaj1TboEGmvSfF7fdoxWyH3RMx7MBHHo", + "zsv8s4Poi5GxCsbBrRJ97Vsvazp84nrz5AN", + "zsmmxrKU6dqWFwUKow1iyovg3gxrgXpEivr", + "zskh1221aRC9WEfb5a59WxffeW34McmZZsw", + "zssAhuj57NnVm4yNFT6o8muRctABkUaBu3L", + "zsi5Yr4Z8HwBvdBqQE8gk7ahExDu95J4oqZ", + "zsy6ryEaxfk8emJ8bGVB7tmwRwBL8cfSqBW" + ], + "foundersRewardSubsidySlowStartInterval": 2, + "foundersRewardSubsidyHalvingInterval": 840000, + "percentTreasuryReward": 12, + "treasuryRewardStartBlockHeight": 139200, + "treasuryRewardAddresses": [ + "zsyF68hcYYNLPj5i4PfQJ1kUY6nsFnZkc82", + "zsfULrmbX7xbhqhAFRffVqCw9RyGv2hqNNG", + "zsoemTfqjicem2QVU8cgBHquKb1o9JR5p4Z", + "zt339oiGL6tTgc9Q71f5g1sFTZf6QiXrRUr" + ], + "treasuryRewardAddressChangeInterval": 50000 + }, + "test": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 1344, + "solutionPreambleSize": 3, + "solver": { + "hash": "equihash", + "args": [ 200, 9, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "testnet", + "payFoundersReward": true, + "percentFoundersReward": 8.5, + "foundersRewardAddresses": [ + "zrH8KT8KUcpKKNBu3fjH4hA84jZBCawErqn", + "zrGsMC4ou1r5Vxy7Dnxg4PfKpansx83BM8g", + "zr6sB2Az36D8CqzeZNavB11WbovsGtJSAZG", + "zrBAG3pXCTDq14nivNK9mW8SfwMNcdmMQpb", + "zrRLwpYRYky4wsvwLVrDp8fs89EBTRhNMB1", + "zrLozMfptTmE3zLP5SrTLyB8TXqH84Agjrr", + "zrMckkaLtVTEUvxj4ouU7BPDGa8xmdTZSVE", + "zrFc897wJXmF7BcEdbvi2mS1bLrcuWYK6hm", + "zrHEnni486u9SNcLWacroSgcdyMA33tfM92", + "zrJ3ymPV3R8Xk4N3BdNb898xvZvARm5K7mq", + "zrDj3P6trx73291krxU51U9QnfkbGxkyJ6E", + "zrJs3vMGFJi9pQCireeSLckJonamBnwTSrY", + "zrKFdXQoAkkycy52EFoWARyzZWx6Kat2Som", + "zrEXbSe79FXA9KRMnJTZUWZdZhNnjcnAdrq", + "zr7iAwfNgJsMpSCmijK3TuVDuNvSmLr1rUz", + "zrDEK7K6cftqSjeyVUH1WqJtBUkXN7GidxH", + "zrRennuq75hyBVU4JymtZk8UcQ1vRPKpmpj", + "zr9HRTL79pKmn5R8fvkC9kucZ4u1bQruLTD", + "zrML8KXpJsa1NVnbJuawX86ZvAn543tWdTT", + "zrLBAkQoxpEtnztSUEcdxnEvuwtgxyAMGX7", + "zr6kPnVzFBYmcBDsWoTrPHRuBxLq21o4zvT", + "zrMY3vdvqs9KSvx9TawvcyuVurt1Jj6GPVo", + "zr9WB1qBpM4nwi1mudUFfjtMNmqzaBQDsXn", + "zrAHbtHDPAqmzWJMQqSYzGyFnDWN3oELZRs", + "zrH1f5K3z7EQ6RWWZ7StCDWHTZwFChBVA2W", + "zrNTacAid9LS4kAqzM4sw1YcF7gLFrzVM7U", + "zrFyZpMVKMeDqbn6A2uUiL9mZmgxuR1pUBg", + "zrD1cqGFGzBcPogFHJvnN4XegvvmbTjA43t", + "zr5A1D7czWkB4pAWfGC5Pux5Ek7anYybdPK", + "zr8yTAxCy6jAdsc6qPvmVEQHbYo25AJKhy9", + "zrFW2YjQw4cABim5kEDwapbSqTz3wW7cWkk", + "zr9nJvNbsrvUTZD41fhqAQeUcgMfqZmAweN", + "zrCx4dXZd5b2tD483Ds4diHpo1QxBMJ76Jr", + "zr6eVeRwU6Puob3K1RfWtva1R458oj8pzkL", + "zr7B92iHtQcobZjGCXo3DAqMQjsn7ka31wE", + "zr8bcemLWAjYuphXSVqtqZWEnJipCB9F5oC", + "zrFzsuPXb7HsFd3srBqtVqnC9GQ94DQubV2", + "zr4yiBobiHjHnCYi75NmYtyoqCV4A3kpHDL", + "zrGVdR4K4F8MfmWxhUiTypK7PTsvHi8uTAh", + "zr7WiCDqCMvUdH1xmMu8YrBMFb2x2E6BX3z", + "zrEFrGWLX4hPHuHRUD3TPbMAJyeSpMSctUc", + "zr5c3f8PTnW8qBFX1GvK2LhyLBBCb1WDdGG", + "zrGkAZkZLqC9QKJR3XomgxNizCpNuAupTeg", + "zrM7muDowiun9tCHhu5K9vcDGfUptuYorfZ", + "zrCsWfwKotWnQmFviqAHAPAJ2jXqZYW966P", + "zrLLB3JB3jozUoMGFEGhjqyVXTpngVQ8c4T", + "zrAEa8YjJ2f3m2VsM1Xa9EwibZxEnRoSLUx", + "zrAdJgp7Cx35xTvB7ABWP8YLTNDArMjP1s3" + ], + "foundersRewardSubsidySlowStartInterval": 2, + "foundersRewardSubsidyHalvingInterval": 840000, + "percentTreasuryReward": 12, + "treasuryRewardStartBlockHeight": 85500, + "treasuryRewardAddresses": [ + "zrRBQ5heytPMN5nY3ssPf3cG4jocXeD8fm1", + "zrRBQ5heytPMN5nY3ssPf3cG4jocXeD8fm1", + "zrRBQ5heytPMN5nY3ssPf3cG4jocXeD8fm1", + "zrRBQ5heytPMN5nY3ssPf3cG4jocXeD8fm1" + ], + "treasuryRewardAddressChangeInterval": 10000 + }, + "regtest": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 1344, + "solutionPreambleSize": 3, + "solver": { + "hash": "equihash", + "args": [ 200, 9, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "regtest", + "payFoundersReward": true, + "percentFoundersReward": 8.5, + "foundersRewardAddresses": [ "zrKmSdqZKZjnARd5e8FfRg4v1m74X7twxGa" ], + "foundersRewardSubsidyHalvingInterval": 2000, + "percentTreasuryReward": 12, + "treasuryRewardStartBlockHeight": 139200, + "treasuryRewardAddresses": [ "zrKmSdqZKZjnARd5e8FfRg4v1m74X7twxGa" ], + "treasuryRewardAddressChangeInterval": 100 + } + }, + "usesZCashAddressFormat": true, + "useBitcoinPayoutHandler": false, + "explorerBlockLink": "http://explorer.zensystem.io/block/$hash$", + "explorerTxLink": "http://explorer.zensystem.io/transactions/{0}", + "explorerAccountLink": "http://explorer.zensystem.io/accounts/{0}" }, "bitcoin-gold": { - "name": "Bitcoin Gold", - "symbol": "BTG", - "family": "equihash", - "networks": { - "main": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 100, - "solutionPreambleSize": 1, - "solver": { - "hash": "equihash", - "args": [ 144, 5, "BgoldPoW" ] - }, - "coinbaseTxNetwork": "main", - "payFoundersReward": false - }, - "test": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 100, - "solutionPreambleSize": 1, - "solver": { - "hash": "equihash", - "args": [ 144, 5, "BgoldPoW" ] - }, - "coinbaseTxNetwork": "testnet", - "payFoundersReward": false - }, - "regtest": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 100, - "solutionPreambleSize": 1, - "solver": { - "hash": "equihash", - "args": [ 144, 5, "BgoldPoW" ] - }, - "coinbaseTxNetwork": "regtest", - "payFoundersReward": false - } - }, - "usesZCashAddressFormat": false, - "useBitcoinPayoutHandler": true, - "explorerBlockLink": "https://explorer.bitcoingold.org/insight/block/$hash$", - "explorerTxLink": "https://explorer.bitcoingold.org/insight/tx/{0}", - "explorerAccountLink": "https://explorer.bitcoingold.org/insight/address/{0}" + "name": "Bitcoin Gold", + "symbol": "BTG", + "family": "equihash", + "networks": { + "main": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 100, + "solutionPreambleSize": 1, + "solver": { + "hash": "equihash", + "args": [ 144, 5, "BgoldPoW" ] + }, + "coinbaseTxNetwork": "main", + "payFoundersReward": false + }, + "test": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 100, + "solutionPreambleSize": 1, + "solver": { + "hash": "equihash", + "args": [ 144, 5, "BgoldPoW" ] + }, + "coinbaseTxNetwork": "testnet", + "payFoundersReward": false + }, + "regtest": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 100, + "solutionPreambleSize": 1, + "solver": { + "hash": "equihash", + "args": [ 144, 5, "BgoldPoW" ] + }, + "coinbaseTxNetwork": "regtest", + "payFoundersReward": false + } + }, + "usesZCashAddressFormat": false, + "useBitcoinPayoutHandler": true, + "explorerBlockLink": "https://explorer.bitcoingold.org/insight/block/$hash$", + "explorerTxLink": "https://explorer.bitcoingold.org/insight/tx/{0}", + "explorerAccountLink": "https://explorer.bitcoingold.org/insight/address/{0}" }, "bithereum": { - "name": "Bithereum", - "symbol": "BTH", - "family": "equihash", - "networks": { - "main": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 100, - "solutionPreambleSize": 1, - "solver": { - "hash": "equihash", - "args": [ 144, 5, "BethdPoW" ] - }, - "coinbaseTxNetwork": "main", - "payFoundersReward": false - }, - "test": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 100, - "solutionPreambleSize": 1, - "solver": { - "hash": "equihash", - "args": [ 144, 5, "BethdPoW" ] - }, - "coinbaseTxNetwork": "testnet", - "payFoundersReward": false - }, - "regtest": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 100, - "solutionPreambleSize": 1, - "solver": { - "hash": "equihash", - "args": [ 144, 5, "BethdPoW" ] - }, - "coinbaseTxNetwork": "regtest", - "payFoundersReward": false - } - }, - "usesZCashAddressFormat": false, - "useBitcoinPayoutHandler": true, - "explorerBlockLink": "https://explorer.bithereum.network/block/$hash$", - "explorerTxLink": "https://explorer.bithereum.network/tx/{0}", - "explorerAccountLink": "https://explorer.bithereum.network/address/{0}" + "name": "Bithereum", + "symbol": "BTH", + "family": "equihash", + "networks": { + "main": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 100, + "solutionPreambleSize": 1, + "solver": { + "hash": "equihash", + "args": [ 144, 5, "BethdPoW" ] + }, + "coinbaseTxNetwork": "main", + "payFoundersReward": false + }, + "test": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 100, + "solutionPreambleSize": 1, + "solver": { + "hash": "equihash", + "args": [ 144, 5, "BethdPoW" ] + }, + "coinbaseTxNetwork": "testnet", + "payFoundersReward": false + }, + "regtest": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 100, + "solutionPreambleSize": 1, + "solver": { + "hash": "equihash", + "args": [ 144, 5, "BethdPoW" ] + }, + "coinbaseTxNetwork": "regtest", + "payFoundersReward": false + } + }, + "usesZCashAddressFormat": false, + "useBitcoinPayoutHandler": true, + "explorerBlockLink": "https://explorer.bithereum.network/block/$hash$", + "explorerTxLink": "https://explorer.bithereum.network/tx/{0}", + "explorerAccountLink": "https://explorer.bithereum.network/address/{0}" }, "minexcoin": { - "name": "Minexcoin", - "symbol": "MNX", - "family": "equihash", - "networks": { - "main": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 68, - "solutionPreambleSize": 1, - "solver": { - "hash": "equihash", - "args": [ 96, 5, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "main", - "payFoundersReward": false - }, - "test": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 68, - "solutionPreambleSize": 1, - "solver": { - "hash": "equihash", - "args": [ 96, 5, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "testnet", - "payFoundersReward": false - }, - "regtest": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 68, - "solutionPreambleSize": 1, - "solver": { - "hash": "equihash", - "args": [ 96, 5, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "regtest", - "payFoundersReward": false - } - }, - "usesZCashAddressFormat": false, - "useBitcoinPayoutHandler": true, - "explorerBlockLink": "https://minexexplorer.com/blocks/view?hash=$hash$", - "explorerTxLink": "https://minexexplorer.com/transactions/view?hash={0}", - "explorerAccountLink": "https://minexexplorer.com/address?hash={0}" + "name": "Minexcoin", + "symbol": "MNX", + "family": "equihash", + "networks": { + "main": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 68, + "solutionPreambleSize": 1, + "solver": { + "hash": "equihash", + "args": [ 96, 5, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "main", + "payFoundersReward": false + }, + "test": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 68, + "solutionPreambleSize": 1, + "solver": { + "hash": "equihash", + "args": [ 96, 5, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "testnet", + "payFoundersReward": false + }, + "regtest": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 68, + "solutionPreambleSize": 1, + "solver": { + "hash": "equihash", + "args": [ 96, 5, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "regtest", + "payFoundersReward": false + } + }, + "usesZCashAddressFormat": false, + "useBitcoinPayoutHandler": true, + "explorerBlockLink": "https://minexexplorer.com/blocks/view?hash=$hash$", + "explorerTxLink": "https://minexexplorer.com/transactions/view?hash={0}", + "explorerAccountLink": "https://minexexplorer.com/address?hash={0}" }, "bitcoin-private": { - "name": "Bitcoin Private", - "symbol": "BTCP", - "family": "equihash", - "networks": { - "main": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 1344, - "solutionPreambleSize": 3, - "solver": { - "hash": "equihash", - "args": [ 200, 9, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "main", - "payFoundersReward": false - }, - "test": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 1344, - "solutionPreambleSize": 3, - "solver": { - "hash": "equihash", - "args": [ 200, 9, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "testnet", - "payFoundersReward": false - }, - "regtest": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "solutionSize": 1344, - "solutionPreambleSize": 3, - "solver": { - "hash": "equihash", - "args": [ 200, 9, "ZcashPoW" ] - }, - "coinbaseTxNetwork": "regtest", - "payFoundersReward": false - } - }, - "usesZCashAddressFormat": true, - "useBitcoinPayoutHandler": false, - "explorerBlockLink": "https://explorer.btcprivate.org/block-index/$hash$", - "explorerTxLink": "https://explorer.btcprivate.org/tx/{0}", - "explorerAccountLink": "https://explorer.btcprivate.org/address/{0}" + "name": "Bitcoin Private", + "symbol": "BTCP", + "family": "equihash", + "networks": { + "main": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 1344, + "solutionPreambleSize": 3, + "solver": { + "hash": "equihash", + "args": [ 200, 9, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "main", + "payFoundersReward": false + }, + "test": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 1344, + "solutionPreambleSize": 3, + "solver": { + "hash": "equihash", + "args": [ 200, 9, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "testnet", + "payFoundersReward": false + }, + "regtest": { + "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "solutionSize": 1344, + "solutionPreambleSize": 3, + "solver": { + "hash": "equihash", + "args": [ 200, 9, "ZcashPoW" ] + }, + "coinbaseTxNetwork": "regtest", + "payFoundersReward": false + } + }, + "usesZCashAddressFormat": true, + "useBitcoinPayoutHandler": false, + "explorerBlockLink": "https://explorer.btcprivate.org/block-index/$hash$", + "explorerTxLink": "https://explorer.btcprivate.org/tx/{0}", + "explorerAccountLink": "https://explorer.btcprivate.org/address/{0}" }, "monero": { - "name": "Monero", - "symbol": "XMR", - "family": "cryptonote", - "hash": "cryptonight", - "hashVariant": 0, - "smallestUnit": 1000000000000, - "addressPrefix": 18, - "addressPrefixTestnet": 53, - "addressPrefixIntegrated": 19, - "addressPrefixIntegratedTestnet": 54, - "explorerBlockLink": "https://chainradar.com/xmr/block/$height$", - "explorerTxLink": "https://chainradar.com/xmr/transaction/{0}" + "name": "Monero", + "symbol": "XMR", + "family": "cryptonote", + "hash": "cryptonight", + "hashVariant": 0, + "smallestUnit": 1000000000000, + "addressPrefix": 18, + "addressPrefixTestnet": 53, + "addressPrefixIntegrated": 19, + "addressPrefixIntegratedTestnet": 54, + "explorerBlockLink": "https://chainradar.com/xmr/block/$height$", + "explorerTxLink": "https://chainradar.com/xmr/transaction/{0}" }, "bittube": { - "name": "Bittube", - "symbol": "TUBE", - "family": "cryptonote", - "hash": "cryptonight-heavy", - "hashVariant": 2, - "smallestUnit": 100000000, - "addressPrefix": 209, - "addressPrefixTestnet": 209, - "addressPrefixIntegrated": 16463, - "addressPrefixIntegratedTestnet": 16463, - "blockrewardMultiplier": 0.7, - "explorerBlockLink": "https://explorer.bit.tube/block/$height$", - "explorerTxLink": "https://explorer.bit.tube/tx/{0}" + "name": "Bittube", + "symbol": "TUBE", + "family": "cryptonote", + "hash": "cryptonight-heavy", + "hashVariant": 2, + "smallestUnit": 100000000, + "addressPrefix": 209, + "addressPrefixTestnet": 209, + "addressPrefixIntegrated": 16463, + "addressPrefixIntegratedTestnet": 16463, + "blockrewardMultiplier": 0.7, + "explorerBlockLink": "https://explorer.bit.tube/block/$height$", + "explorerTxLink": "https://explorer.bit.tube/tx/{0}" }, "aeon": { - "name": "Aeon", - "symbol": "AEON", - "family": "cryptonote", - "hash": "cryptonight-lite", - "hashVariant": 0, - "smallestUnit": 100000000, - "addressPrefix": 178, - "addressPrefixTestnet": 1062, - "addressPrefixIntegrated": 10035, - "addressPrefixIntegratedTestnet": 11303, - "explorerBlockLink": "https://aeonblocks.com/block/$height$", - "explorerTxLink": "https://aeonblocks.com/tx/{0}" + "name": "Aeon", + "symbol": "AEON", + "family": "cryptonote", + "hash": "cryptonight-lite", + "hashVariant": 0, + "smallestUnit": 100000000, + "addressPrefix": 178, + "addressPrefixTestnet": 1062, + "addressPrefixIntegrated": 10035, + "addressPrefixIntegratedTestnet": 11303, + "explorerBlockLink": "https://aeonblocks.com/block/$height$", + "explorerTxLink": "https://aeonblocks.com/tx/{0}" }, "ethereum": { - "name": "Ethereum", - "symbol": "ETH", - "family": "ethereum", - "explorerBlockLinks": { - "block": "https://etherscan.io/block/$height$", - "uncle": "https://etherscan.io/uncle/$height$" - }, - "explorerTxLink": "https://etherscan.io/tx/{0}", - "explorerAccountLink": "https://etherscan.io/address/{0}" + "name": "Ethereum", + "symbol": "ETH", + "family": "ethereum", + "explorerBlockLinks": { + "block": "https://etherscan.io/block/$height$", + "uncle": "https://etherscan.io/uncle/$height$" + }, + "explorerTxLink": "https://etherscan.io/tx/{0}", + "explorerAccountLink": "https://etherscan.io/address/{0}" }, "ethereum-classic": { - "name": "Ethereum Classic", - "symbol": "ETC", - "family": "ethereum", - "explorerBlockLinks": { - "block": "https://gastracker.io/block/$height$", - "uncle": "https://gastracker.io/uncle/$height$" - }, - "explorerTxLink": "https://gastracker.io/tx/{0}", - "explorerAccountLink": "https://gastracker.io/addr/{0}" + "name": "Ethereum Classic", + "symbol": "ETC", + "family": "ethereum", + "explorerBlockLinks": { + "block": "https://gastracker.io/block/$height$", + "uncle": "https://gastracker.io/uncle/$height$" + }, + "explorerTxLink": "https://gastracker.io/tx/{0}", + "explorerAccountLink": "https://gastracker.io/addr/{0}" } - } \ No newline at end of file +} From df588083a659c37db31cc3b62b293dd1e9f9eeca Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 6 May 2019 23:34:45 +0200 Subject: [PATCH 143/178] Allow overriding getblocktemplate RPC arguments from pool-config --- src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs | 2 +- .../Bitcoin/Configuration/BitcoinPoolConfigExtra.cs | 6 ++++++ .../Equihash/Configuration/EquihashPoolConfigExtra.cs | 6 ++++++ src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index f87122b83..2e58ceaa4 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -58,7 +58,7 @@ protected async Task> GetBlockTemplateAsync() logger.LogInvoke(); var result = await daemon.ExecuteCmdAnyAsync(logger, - BitcoinCommands.GetBlockTemplate, getBlockTemplateParams); + BitcoinCommands.GetBlockTemplate, extraPoolConfig?.GBTArgs ?? (object) getBlockTemplateParams); return result; } diff --git a/src/Miningcore/Blockchain/Bitcoin/Configuration/BitcoinPoolConfigExtra.cs b/src/Miningcore/Blockchain/Bitcoin/Configuration/BitcoinPoolConfigExtra.cs index 05a22da4f..d3dbed7b3 100644 --- a/src/Miningcore/Blockchain/Bitcoin/Configuration/BitcoinPoolConfigExtra.cs +++ b/src/Miningcore/Blockchain/Bitcoin/Configuration/BitcoinPoolConfigExtra.cs @@ -19,6 +19,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ using Miningcore.Configuration; +using Newtonsoft.Json.Linq; namespace Miningcore.Blockchain.Bitcoin.Configuration { @@ -47,5 +48,10 @@ public class BitcoinPoolConfigExtra /// Blocktemplate stream published via ZMQ /// public ZmqPubSubEndpointConfig BtStream { get; set; } + + /// + /// Custom Arguments for getblocktemplate RPC + /// + public JToken GBTArgs { get; set; } } } diff --git a/src/Miningcore/Blockchain/Equihash/Configuration/EquihashPoolConfigExtra.cs b/src/Miningcore/Blockchain/Equihash/Configuration/EquihashPoolConfigExtra.cs index acb7e99ae..1ee9ab5b7 100644 --- a/src/Miningcore/Blockchain/Equihash/Configuration/EquihashPoolConfigExtra.cs +++ b/src/Miningcore/Blockchain/Equihash/Configuration/EquihashPoolConfigExtra.cs @@ -19,6 +19,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Miningcore.Blockchain.Equihash.Configuration { @@ -29,5 +30,10 @@ public class EquihashPoolConfigExtra /// [JsonProperty("z-address")] public string ZAddress { get; set; } + + /// + /// Custom Arguments for getblocktemplate RPC + /// + public JToken GBTArgs { get; set; } } } diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index 66655e20b..b90d0f42c 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -62,7 +62,7 @@ private async Task> GetBlockTemplateAsync( var subsidyResponse = await daemon.ExecuteCmdAnyAsync(logger, BitcoinCommands.GetBlockSubsidy); var result = await daemon.ExecuteCmdAnyAsync(logger, - BitcoinCommands.GetBlockTemplate, getBlockTemplateParams); + BitcoinCommands.GetBlockTemplate, extraPoolConfig?.GBTArgs ?? (object) getBlockTemplateParams); if(subsidyResponse.Error == null && result.Error == null && result.Response != null) result.Response.Subsidy = subsidyResponse.Response; From 3131dcc6b27c7e1b88c8aa96469d153ccfc2462a Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 6 May 2019 23:56:24 +0200 Subject: [PATCH 144/178] Remove unnecessary default GBT args --- .../Blockchain/Bitcoin/BitcoinJobManagerBase.cs | 3 +-- src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs | 8 +------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index 204a47e9b..9ca7be304 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -85,11 +85,10 @@ protected BitcoinJobManagerBase( protected Network network; protected IDestination poolAddressDestination; - protected object[] getBlockTemplateParams = + protected object[] getBlockTemplateParams = { new { - capabilities = new[] { "coinbasetxn", "workid", "coinbase/append" }, rules = new[] { "segwit" } } }; diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index b90d0f42c..7648e675b 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -34,13 +34,7 @@ public EquihashJobManager( IMessageBus messageBus, IExtraNonceProvider extraNonceProvider) : base(ctx, clock, messageBus, extraNonceProvider) { - getBlockTemplateParams = new object[] - { - new - { - capabilities = new[] { "coinbasetxn", "workid", "coinbase/append" }, - } - }; + getBlockTemplateParams = null; } private EquihashCoinTemplate coin; From d6a7aa10b3651516aca295a29529063c8fa0e6c3 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 7 May 2019 10:33:37 +0200 Subject: [PATCH 145/178] Fix linux build of libmultihash/Makefile --- src/Native/libmultihash/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Native/libmultihash/Makefile b/src/Native/libmultihash/Makefile index a7dc300b4..acb01562d 100644 --- a/src/Native/libmultihash/Makefile +++ b/src/Native/libmultihash/Makefile @@ -12,7 +12,7 @@ OBJECTS = bcrypt.o blake.o blake2s.o c11.o dcrypt.o fresh.o \ sha3/sph_luffa.o sha3/sph_shabal.o sha3/sph_shavite.o sha3/sph_simd.o sha3/sph_skein.o sha3/sph_whirlpool.o \ sha3/sph_haval.o sha3/sph_sha2.o sha3/sph_sha2big.o sha3/sph_blake2s.o sha3/sm3.o \ sha3/extra.o sha3/gost_streebog.o sha3/sph_tiger.o sha3/SWIFFTX.o KeccakP-800-reference.o \ - shavite3.o skein.o x11.o x13.o x15.o x17.o x16r.o x16s.o x22i.o x21s.o odocrypt.o \ + shavite3.o skein.o x11.o x13.o x15.o x17.o x16r.o x16s.o x21s.o odocrypt.o \ Lyra2.o Lyra2RE.o Sponge.o geek.o \ equi/util.o equi/support/cleanse.o equi/random.o \ equi/uint256.o equi/arith_uint256.o equi/crypto/hmac_sha512.o \ From dd2fa4a5eebb7977c3ca3e3b1cc250b88bc68dc0 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 7 May 2019 20:24:09 +0200 Subject: [PATCH 146/178] Cleanup --- src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs | 6 ------ src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs | 1 - src/Miningcore/Blockchain/JobManagerBase.cs | 5 ----- 3 files changed, 12 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index 9ca7be304..eb95b114f 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -25,7 +25,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using System.Net; using System.Reactive; using System.Reactive.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using Autofac; @@ -33,13 +32,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using Miningcore.Blockchain.Bitcoin.DaemonResponses; using Miningcore.Configuration; using Miningcore.Contracts; -using Miningcore.Crypto; -using Miningcore.Crypto.Hashing.Algorithms; using Miningcore.DaemonInterface; using Miningcore.Extensions; -using Miningcore.JsonRpc; using Miningcore.Messaging; -using Miningcore.Notifications; using Miningcore.Notifications.Messages; using Miningcore.Stratum; using Miningcore.Time; @@ -47,7 +42,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using NBitcoin; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using NLog; namespace Miningcore.Blockchain.Bitcoin { diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index 7648e675b..26c0fbc7d 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -16,7 +16,6 @@ using Miningcore.Extensions; using Miningcore.JsonRpc; using Miningcore.Messaging; -using Miningcore.Notifications.Messages; using Miningcore.Stratum; using Miningcore.Time; using NBitcoin; diff --git a/src/Miningcore/Blockchain/JobManagerBase.cs b/src/Miningcore/Blockchain/JobManagerBase.cs index fa3ce2885..fec8f548c 100644 --- a/src/Miningcore/Blockchain/JobManagerBase.cs +++ b/src/Miningcore/Blockchain/JobManagerBase.cs @@ -19,13 +19,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ using System; -using System.IO; -using System.IO.Compression; using System.Reactive; -using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reactive.Subjects; -using System.Text; using System.Threading; using System.Threading.Tasks; using Autofac; @@ -35,7 +31,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using Miningcore.Notifications.Messages; using Miningcore.Util; using NLog; -using ZeroMQ; using Contract = Miningcore.Contracts.Contract; namespace Miningcore.Blockchain From 2f3dcfafdeb6314c28fedacd544642b9c70290ed Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 7 May 2019 20:26:45 +0200 Subject: [PATCH 147/178] Formatting --- src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index eb95b114f..d70a81948 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -79,7 +79,7 @@ protected BitcoinJobManagerBase( protected Network network; protected IDestination poolAddressDestination; - protected object[] getBlockTemplateParams = + protected object[] getBlockTemplateParams = { new { From dbbf92605de152ebd32eae3d3a76a30c0cfc1a51 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 8 May 2019 08:03:13 +0200 Subject: [PATCH 148/178] Blocktemplate checks --- src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs | 8 ++++---- src/Miningcore/Blockchain/CoinMetaData.cs | 4 ++-- src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index 2e58ceaa4..9f18517c8 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -103,12 +103,12 @@ private BitcoinJob CreateJob() } var blockTemplate = response.Response; - var job = currentJob; + var isNew = job == null || - (blockTemplate != null && - job.BlockTemplate?.PreviousBlockhash != blockTemplate.PreviousBlockhash && - blockTemplate.Height > job.BlockTemplate?.Height); + (blockTemplate != null && + (job.BlockTemplate?.PreviousBlockhash != blockTemplate.PreviousBlockhash || + blockTemplate.Height > job.BlockTemplate?.Height)); if(isNew) messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); diff --git a/src/Miningcore/Blockchain/CoinMetaData.cs b/src/Miningcore/Blockchain/CoinMetaData.cs index 928d6ec2b..ffd72cc5a 100644 --- a/src/Miningcore/Blockchain/CoinMetaData.cs +++ b/src/Miningcore/Blockchain/CoinMetaData.cs @@ -2,7 +2,7 @@ namespace Miningcore.Blockchain { - public class DevDonation + public static class DevDonation { public const decimal Percent = 0.1m; @@ -25,7 +25,7 @@ public class DevDonation { "ZEN", "znigQacfTvRiwD2TRhwkBHLNchQ2AZisD94" }, { "BTG", "GRao6KHQ8a4GUjAZRVbeCLfRbSkJQQaeMg" }, { "XVG", "D5xPoHLM6HPkwWSqAweECTSQirJBmRjS8i" }, - { "XMR", "475YVJbPHPedudkhrcNp1wDcLMTGYusGPF5fqE7XjnragVLPdqbCHBdZg3dF4dN9hXMjjvGbykS6a77dTAQvGrpiQqHp2eH" }, + { "XMR", "46S2AEwYmD9fnmZkxCpXf1T3U3DyEq3Ekb8Lg9kgUMGABn9Fp9q5nE2fBcXebrjrXfZHy5uC5HfLE6X4WLtSm35wUr9Mh46" }, { "ETN", "etnkQJwBCjmR1MfkU8D355ZWxxLMhs8miPrtKHWN4U3uUowq9ugeKccVBoEG3n13n74us5AkT8tEoTog46w4HBgn8sMuBRhm9h" }, { "RVN", "RQPJF65UoodQ2aZUkfnXoeX6gib3GNwm9u" }, { "TUBE", "bxdAFKYA5sJYKM3zcn3SLaLRjsFF582VE1Uv5NChrVLm6o6UF4SdbZBZLrTBD6yEFZDzuTQGBCa8FLpX8charjxH2G3iMRX6R" }, diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index 26c0fbc7d..d1bcf28df 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -121,12 +121,12 @@ private EquihashJob CreateJob() } var blockTemplate = response.Response; - var job = currentJob; + var isNew = job == null || - (blockTemplate != null && - job.BlockTemplate?.PreviousBlockhash != blockTemplate.PreviousBlockhash && - blockTemplate.Height > job.BlockTemplate?.Height); + (blockTemplate != null && + (job.BlockTemplate?.PreviousBlockhash != blockTemplate.PreviousBlockhash || + blockTemplate.Height > job.BlockTemplate?.Height)); if(isNew) messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); From 08fb1eda589e7585879ef6379cecf7fb489f407d Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 8 May 2019 11:03:54 +0200 Subject: [PATCH 149/178] Job-Refresh logging refactor --- .../Blockchain/Bitcoin/BitcoinJobManager.cs | 2 +- .../Bitcoin/BitcoinJobManagerBase.cs | 20 +++++++++++-------- src/Miningcore/Blockchain/Constants.cs | 13 ++++++++++++ .../Cryptonote/CryptonoteJobManager.cs | 14 ++++++------- .../Blockchain/Equihash/EquihashJobManager.cs | 2 +- 5 files changed, 34 insertions(+), 17 deletions(-) create mode 100644 src/Miningcore/Blockchain/Constants.cs diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index 9f18517c8..0e3772b42 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -127,7 +127,7 @@ private BitcoinJob CreateJob() if(isNew) { if(via != null) - logger.Info(() => $"Detected new block {blockTemplate.Height} via {via}"); + logger.Info(() => $"Detected new block {blockTemplate.Height} via [{via}]"); else logger.Info(() => $"Detected new block {blockTemplate.Height}"); diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index d70a81948..e23c90c49 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -95,7 +95,7 @@ protected virtual void SetupJobUpdates() var triggers = new List> { - blockSubmission.Select(x => (false, "Block-submission", (string) null)) + blockSubmission.Select(x => (false, JobRefreshBy.BlockSubmission, (string) null)) }; if(extraPoolConfig?.BtStream == null) @@ -127,7 +127,7 @@ protected virtual void SetupJobUpdates() } }) .DistinctUntilChanged() - .Select(_ => (false, "ZMQ pub/sub", (string) null)) + .Select(_ => (false, JobRefreshBy.PubSub, (string) null)) .Publish() .RefCount(); @@ -147,7 +147,7 @@ protected virtual void SetupJobUpdates() triggers.Add(Observable.Timer(TimeSpan.FromMilliseconds(pollingInterval)) .TakeUntil(pollTimerRestart) - .Select(_ => (false, "RPC polling", (string) null)) + .Select(_ => (false, JobRefreshBy.Poll, (string) null)) .Repeat()); } @@ -155,14 +155,14 @@ protected virtual void SetupJobUpdates() { // get initial blocktemplate triggers.Add(Observable.Interval(TimeSpan.FromMilliseconds(1000)) - .Select(_ => (false, "Initial template", (string) null)) + .Select(_ => (false, JobRefreshBy.Initial, (string) null)) .TakeWhile(_ => !hasInitialBlockTemplate)); } // periodically update transactions for current template triggers.Add(Observable.Timer(jobRebroadcastTimeout) .TakeUntil(pollTimerRestart) - .Select(_ => (true, "Job-Refresh", (string) null)) + .Select(_ => (true, JobRefreshBy.PollRefresh, (string) null)) .Repeat()); } @@ -175,7 +175,11 @@ protected virtual void SetupJobUpdates() var interval = TimeSpan.FromSeconds(Math.Max(1, poolConfig.JobRebroadcastTimeout - 0.1d)); triggers.Add(btStream - .Select(json => (!lastJobRebroadcast.HasValue || (clock.Now - lastJobRebroadcast >= interval), "BT-Stream", json)) + .Select(json => + { + var force = !lastJobRebroadcast.HasValue || (clock.Now - lastJobRebroadcast >= interval); + return (force, !force ? JobRefreshBy.BlockTemplateStream : JobRefreshBy.BlockTemplateStreamRefresh, json); + }) .Publish() .RefCount()); } @@ -183,14 +187,14 @@ protected virtual void SetupJobUpdates() else { triggers.Add(btStream - .Select(json => (false, "BT-Stream", json)) + .Select(json => (false, JobRefreshBy.BlockTemplateStream, json)) .Publish() .RefCount()); } // get initial blocktemplate triggers.Add(Observable.Interval(TimeSpan.FromMilliseconds(1000)) - .Select(_ => (false, "Initial template", (string) null)) + .Select(_ => (false, JobRefreshBy.Initial, (string) null)) .TakeWhile(_ => !hasInitialBlockTemplate)); } diff --git a/src/Miningcore/Blockchain/Constants.cs b/src/Miningcore/Blockchain/Constants.cs new file mode 100644 index 000000000..a91cb4cc8 --- /dev/null +++ b/src/Miningcore/Blockchain/Constants.cs @@ -0,0 +1,13 @@ +namespace Miningcore.Blockchain +{ + public static class JobRefreshBy + { + public const string Initial = "INIT"; + public const string Poll = "POLL"; + public const string PollRefresh = "POLL-R"; + public const string PubSub = "ZMQ"; + public const string BlockTemplateStream = "BTS"; + public const string BlockTemplateStreamRefresh = "BTS-R"; + public const string BlockSubmission = "BLOCK"; + } +} diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs index 93e3d33f7..a0a229bf8 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs @@ -108,7 +108,7 @@ protected async Task UpdateJob(string via = null, string json = null) messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); if(via != null) - logger.Info(() => $"Detected new block {blockTemplate.Height} via {via}"); + logger.Info(() => $"Detected new block {blockTemplate.Height} via [{via}]"); else logger.Info(() => $"Detected new block {blockTemplate.Height}"); @@ -549,7 +549,7 @@ protected virtual void SetupJobUpdates() var triggers = new List> { - blockSubmission.Select(x => ("Block-submission", (string) null)) + blockSubmission.Select(x => (JobRefreshBy.BlockSubmission, (string) null)) }; if(extraPoolConfig?.BtStream == null) @@ -581,7 +581,7 @@ protected virtual void SetupJobUpdates() } }) .DistinctUntilChanged() - .Select(_ => ("ZMQ pub/sub", (string) null)) + .Select(_ => (JobRefreshBy.PubSub, (string) null)) .Publish() .RefCount(); @@ -601,7 +601,7 @@ protected virtual void SetupJobUpdates() triggers.Add(Observable.Timer(TimeSpan.FromMilliseconds(pollingInterval)) .TakeUntil(pollTimerRestart) - .Select(_ => ("RPC polling", (string) null)) + .Select(_ => (JobRefreshBy.Poll, (string) null)) .Repeat()); } @@ -609,7 +609,7 @@ protected virtual void SetupJobUpdates() { // get initial blocktemplate triggers.Add(Observable.Interval(TimeSpan.FromMilliseconds(1000)) - .Select(_ => ("Initial template", (string) null)) + .Select(_ => (JobRefreshBy.Initial, (string) null)) .TakeWhile(_ => !hasInitialBlockTemplate)); } } @@ -617,13 +617,13 @@ protected virtual void SetupJobUpdates() else { triggers.Add(BtStreamSubscribe(extraPoolConfig.BtStream) - .Select(json => ("BT-Stream", json)) + .Select(json => (JobRefreshBy.BlockTemplateStream, json)) .Publish() .RefCount()); // get initial blocktemplate triggers.Add(Observable.Interval(TimeSpan.FromMilliseconds(1000)) - .Select(_ => ("Initial template", (string) null)) + .Select(_ => (JobRefreshBy.Initial, (string) null)) .TakeWhile(_ => !hasInitialBlockTemplate)); } diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index d1bcf28df..5919dbf17 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -144,7 +144,7 @@ private EquihashJob CreateJob() if(isNew) { if(via != null) - logger.Info(() => $"Detected new block {blockTemplate.Height} via {via}"); + logger.Info(() => $"Detected new block {blockTemplate.Height} via [{via}]"); else logger.Info(() => $"Detected new block {blockTemplate.Height}"); From 3cdc96a2ee188a03ebf5db23b7e3ca147132ca9a Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 8 May 2019 18:16:41 +0200 Subject: [PATCH 150/178] Update Database Schema and README for PostgreSQL 11 which is now mandatory for new installations --- README.md | 2 +- src/Miningcore/Persistence/Postgres/Scripts/createdb.sql | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b907d2caa..f9aca7e85 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ This software comes with a built-in donation of 0.1% per block-reward to support ### Runtime Requirements on Linux - [.Net Core 2.2 SDK](https://www.microsoft.com/net/download/core) -- [PostgreSQL Database](https://www.postgresql.org/) +- [PostgreSQL 11 (or higher) Database](https://www.postgresql.org/) - Coin Daemon (per pool) - Miningcore needs to be built from source on Linux. Refer to the section further down below for instructions. diff --git a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql index 7f4ced3a0..d6ebc72ef 100644 --- a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql +++ b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql @@ -12,11 +12,11 @@ CREATE TABLE shares ipaddress TEXT NOT NULL, source TEXT NULL, created TIMESTAMP NOT NULL -); +) PARTITION BY LIST (poolid); -CREATE INDEX IDX_SHARES_POOL_MINER on shares(poolid, miner); -CREATE INDEX IDX_SHARES_POOL_CREATED ON shares(poolid, created); -CREATE INDEX IDX_SHARES_POOL_MINER_DIFFICULTY on shares(poolid, miner, difficulty); +CREATE INDEX IDX_SHARES_MINER on shares(poolid, miner); +CREATE INDEX IDX_SHARES_CREATED ON shares(poolid, created); +CREATE INDEX IDX_SHARES_MINER_DIFFICULTY on shares(poolid, miner, difficulty); CREATE TABLE blocks ( From 6cbe5447c0fc359fa6c55c7d7832ca27cbc9a231 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 8 May 2019 19:20:26 +0200 Subject: [PATCH 151/178] Revert "Update Database Schema and README for PostgreSQL 11 which is now mandatory for new installations" This reverts commit 3cdc96a2ee188a03ebf5db23b7e3ca147132ca9a. --- README.md | 2 +- src/Miningcore/Persistence/Postgres/Scripts/createdb.sql | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f9aca7e85..b907d2caa 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ This software comes with a built-in donation of 0.1% per block-reward to support ### Runtime Requirements on Linux - [.Net Core 2.2 SDK](https://www.microsoft.com/net/download/core) -- [PostgreSQL 11 (or higher) Database](https://www.postgresql.org/) +- [PostgreSQL Database](https://www.postgresql.org/) - Coin Daemon (per pool) - Miningcore needs to be built from source on Linux. Refer to the section further down below for instructions. diff --git a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql index d6ebc72ef..7f4ced3a0 100644 --- a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql +++ b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql @@ -12,11 +12,11 @@ CREATE TABLE shares ipaddress TEXT NOT NULL, source TEXT NULL, created TIMESTAMP NOT NULL -) PARTITION BY LIST (poolid); +); -CREATE INDEX IDX_SHARES_MINER on shares(poolid, miner); -CREATE INDEX IDX_SHARES_CREATED ON shares(poolid, created); -CREATE INDEX IDX_SHARES_MINER_DIFFICULTY on shares(poolid, miner, difficulty); +CREATE INDEX IDX_SHARES_POOL_MINER on shares(poolid, miner); +CREATE INDEX IDX_SHARES_POOL_CREATED ON shares(poolid, created); +CREATE INDEX IDX_SHARES_POOL_MINER_DIFFICULTY on shares(poolid, miner, difficulty); CREATE TABLE blocks ( From 830444d8318c9c33db36b5d72fefb8398c4b7fe2 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 8 May 2019 21:26:25 +0200 Subject: [PATCH 152/178] Logging --- src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs | 2 +- src/Miningcore/Blockchain/Constants.cs | 1 + .../Blockchain/Cryptonote/CryptonoteJobManager.cs | 2 +- src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs | 2 +- src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs | 8 ++++---- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index 0e3772b42..08b3f9539 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -127,7 +127,7 @@ private BitcoinJob CreateJob() if(isNew) { if(via != null) - logger.Info(() => $"Detected new block {blockTemplate.Height} via [{via}]"); + logger.Info(() => $"Detected new block {blockTemplate.Height} [{via}]"); else logger.Info(() => $"Detected new block {blockTemplate.Height}"); diff --git a/src/Miningcore/Blockchain/Constants.cs b/src/Miningcore/Blockchain/Constants.cs index a91cb4cc8..3ec3890c1 100644 --- a/src/Miningcore/Blockchain/Constants.cs +++ b/src/Miningcore/Blockchain/Constants.cs @@ -8,6 +8,7 @@ public static class JobRefreshBy public const string PubSub = "ZMQ"; public const string BlockTemplateStream = "BTS"; public const string BlockTemplateStreamRefresh = "BTS-R"; + public const string WebSocket = "WS"; public const string BlockSubmission = "BLOCK"; } } diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs index a0a229bf8..2bec67a31 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs @@ -108,7 +108,7 @@ protected async Task UpdateJob(string via = null, string json = null) messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); if(via != null) - logger.Info(() => $"Detected new block {blockTemplate.Height} via [{via}]"); + logger.Info(() => $"Detected new block {blockTemplate.Height} [{via}]"); else logger.Info(() => $"Detected new block {blockTemplate.Height}"); diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index 5919dbf17..5bc42fb0c 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -144,7 +144,7 @@ private EquihashJob CreateJob() if(isNew) { if(via != null) - logger.Info(() => $"Detected new block {blockTemplate.Height} via [{via}]"); + logger.Info(() => $"Detected new block {blockTemplate.Height} [{via}]"); else logger.Info(() => $"Detected new block {blockTemplate.Height}"); diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs index ba769cced..e6f3c48e4 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs @@ -705,7 +705,7 @@ protected virtual async Task SetupJobUpdatesAsync() .Do(isNew => { if(isNew) - logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected via WebSocket"); + logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected [{JobRefreshBy.WebSocket}]"); }) .Where(isNew => isNew) .Select(_ => GetJobParamsForStratum(true)) @@ -748,7 +748,7 @@ protected virtual async Task SetupJobUpdatesAsync() .Do(isNew => { if(isNew) - logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected via WebSocket"); + logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected [WS]"); }) .Where(isNew => isNew) .Select(_ => GetJobParamsForStratum(true)) @@ -767,7 +767,7 @@ protected virtual async Task SetupJobUpdatesAsync() .Do(isNew => { if(isNew) - logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected via RPC-Polling"); + logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected [{JobRefreshBy.Poll}]"); }) .Where(isNew => isNew) .Select(_ => GetJobParamsForStratum(true)) @@ -787,7 +787,7 @@ protected virtual async Task SetupJobUpdatesAsync() .Do(isNew => { if(isNew) - logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected via BT-Stream"); + logger.Info(() => $"New work at height {currentJob.BlockTemplate.Height} and header {currentJob.BlockTemplate.Header} detected [{JobRefreshBy.BlockTemplateStream}]"); }) .Where(isNew => isNew) .Select(_ => GetJobParamsForStratum(true)) From 76ce86cbd6c3caf8a3b2e6d401795d598ec9c630 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Fri, 10 May 2019 19:04:59 +0200 Subject: [PATCH 153/178] Refactoring --- src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs | 2 +- .../Blockchain/Bitcoin/BitcoinJobManagerBase.cs | 8 ++++---- src/Miningcore/Blockchain/Constants.cs | 2 +- .../Blockchain/Cryptonote/CryptonoteJobManager.cs | 9 +++++---- src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs | 2 +- src/Miningcore/Blockchain/JobManagerBase.cs | 7 ++++++- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index 08b3f9539..1fa423811 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -266,7 +266,7 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob { logger.Info(() => $"Daemon accepted block {share.BlockHeight} [{share.BlockHash}] submitted by {minerName}"); - blockSubmissionSubject.OnNext(Unit.Default); + OnBlockFound(); // persist the coinbase transaction-hash to allow the payment processor // to verify later on that the pool has received the reward for the block diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index e23c90c49..b5d5ed466 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -90,12 +90,12 @@ protected BitcoinJobManagerBase( protected virtual void SetupJobUpdates() { jobRebroadcastTimeout = TimeSpan.FromSeconds(Math.Max(1, poolConfig.JobRebroadcastTimeout)); - var blockSubmission = blockSubmissionSubject.Synchronize(); - var pollTimerRestart = blockSubmissionSubject.Synchronize(); + var blockFound = blockFoundSubject.Synchronize(); + var pollTimerRestart = blockFoundSubject.Synchronize(); var triggers = new List> { - blockSubmission.Select(x => (false, JobRefreshBy.BlockSubmission, (string) null)) + blockFound.Select(x => (false, JobRefreshBy.BlockFound, (string) null)) }; if(extraPoolConfig?.BtStream == null) @@ -132,7 +132,7 @@ protected virtual void SetupJobUpdates() .RefCount(); pollTimerRestart = Observable.Merge( - blockSubmission, + blockFound, blockNotify.Select(_ => Unit.Default)) .Publish() .RefCount(); diff --git a/src/Miningcore/Blockchain/Constants.cs b/src/Miningcore/Blockchain/Constants.cs index 3ec3890c1..8682b64b0 100644 --- a/src/Miningcore/Blockchain/Constants.cs +++ b/src/Miningcore/Blockchain/Constants.cs @@ -9,6 +9,6 @@ public static class JobRefreshBy public const string BlockTemplateStream = "BTS"; public const string BlockTemplateStreamRefresh = "BTS-R"; public const string WebSocket = "WS"; - public const string BlockSubmission = "BLOCK"; + public const string BlockFound = "BLOCK"; } } diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs index 2bec67a31..90f26dedb 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs @@ -348,7 +348,8 @@ public async ValueTask SubmitShareAsync(StratumClient worker, if(share.IsBlockCandidate) { logger.Info(() => $"Daemon accepted block {share.BlockHeight} [{share.BlockHash.Substring(0, 6)}] submitted by {context.Miner}"); - blockSubmissionSubject.OnNext(Unit.Default); + + OnBlockFound(); share.TransactionConfirmationData = share.BlockHash; } @@ -544,12 +545,12 @@ private void ConfigureRewards() protected virtual void SetupJobUpdates() { - var blockSubmission = blockSubmissionSubject.Synchronize(); - var pollTimerRestart = blockSubmissionSubject.Synchronize(); + var blockSubmission = blockFoundSubject.Synchronize(); + var pollTimerRestart = blockFoundSubject.Synchronize(); var triggers = new List> { - blockSubmission.Select(x => (JobRefreshBy.BlockSubmission, (string) null)) + blockSubmission.Select(x => (JobRefreshBy.BlockFound, (string) null)) }; if(extraPoolConfig?.BtStream == null) diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index 5bc42fb0c..55f895ecd 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -283,7 +283,7 @@ public override async ValueTask SubmitShareAsync(StratumClient worker, ob { logger.Info(() => $"Daemon accepted block {share.BlockHeight} [{share.BlockHash}] submitted by {minerName}"); - blockSubmissionSubject.OnNext(Unit.Default); + OnBlockFound(); // persist the coinbase transaction-hash to allow the payment processor // to verify later on that the pool has received the reward for the block diff --git a/src/Miningcore/Blockchain/JobManagerBase.cs b/src/Miningcore/Blockchain/JobManagerBase.cs index fec8f548c..169930f53 100644 --- a/src/Miningcore/Blockchain/JobManagerBase.cs +++ b/src/Miningcore/Blockchain/JobManagerBase.cs @@ -56,7 +56,7 @@ protected JobManagerBase(IComponentContext ctx, IMessageBus messageBus) protected ILogger logger; protected PoolConfig poolConfig; protected bool hasInitialBlockTemplate = false; - protected Subject blockSubmissionSubject = new Subject(); + protected Subject blockFoundSubject = new Subject(); protected abstract void ConfigureDaemons(); @@ -101,6 +101,11 @@ protected IObservable BtStreamSubscribe(ZmqPubSubEndpointConfig config) .RefCount(); } + protected virtual void OnBlockFound() + { + blockFoundSubject.OnNext(Unit.Default); + } + protected abstract Task AreDaemonsHealthyAsync(); protected abstract Task AreDaemonsConnectedAsync(); protected abstract Task EnsureDaemonsSynchedAsync(CancellationToken ct); From 61e2d49424cb1c856009b69d4e75d6d6609b22b1 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sat, 11 May 2019 12:13:55 +0200 Subject: [PATCH 154/178] Refactor --- .../Blockchain/Bitcoin/BitcoinJobManager.cs | 34 +++++++++-------- .../Blockchain/Equihash/EquihashJobManager.cs | 37 ++++++++++--------- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index 1fa423811..49825f690 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -93,7 +93,9 @@ private BitcoinJob CreateJob() if(forceUpdate) lastJobRebroadcast = clock.Now; - var response = string.IsNullOrEmpty(json) ? await GetBlockTemplateAsync() : GetBlockTemplateFromJson(json); + var response = string.IsNullOrEmpty(json) ? + await GetBlockTemplateAsync() : + GetBlockTemplateFromJson(json); // may happen if daemon is currently not connected to peers if(response.Error != null) @@ -124,21 +126,6 @@ private BitcoinJob CreateJob() lock(jobLock) { - if(isNew) - { - if(via != null) - logger.Info(() => $"Detected new block {blockTemplate.Height} [{via}]"); - else - logger.Info(() => $"Detected new block {blockTemplate.Height}"); - - // update stats - BlockchainStats.LastNetworkBlockTime = clock.Now; - BlockchainStats.BlockHeight = blockTemplate.Height; - BlockchainStats.NetworkDifficulty = job.Difficulty; - BlockchainStats.NextNetworkTarget = blockTemplate.Target; - BlockchainStats.NextNetworkBits = blockTemplate.Bits; - } - validJobs.Insert(0, job); // trim active jobs @@ -146,6 +133,21 @@ private BitcoinJob CreateJob() validJobs.RemoveAt(validJobs.Count - 1); } + if(isNew) + { + if(via != null) + logger.Info(() => $"Detected new block {blockTemplate.Height} [{via}]"); + else + logger.Info(() => $"Detected new block {blockTemplate.Height}"); + + // update stats + BlockchainStats.LastNetworkBlockTime = clock.Now; + BlockchainStats.BlockHeight = blockTemplate.Height; + BlockchainStats.NetworkDifficulty = job.Difficulty; + BlockchainStats.NextNetworkTarget = blockTemplate.Target; + BlockchainStats.NextNetworkBits = blockTemplate.Bits; + } + currentJob = job; } diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index 55f895ecd..6c63218a7 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -111,7 +111,9 @@ private EquihashJob CreateJob() if(forceUpdate) lastJobRebroadcast = clock.Now; - var response = string.IsNullOrEmpty(json) ? await GetBlockTemplateAsync() : GetBlockTemplateFromJson(json); + var response = string.IsNullOrEmpty(json) ? + await GetBlockTemplateAsync() : + GetBlockTemplateFromJson(json); // may happen if daemon is currently not connected to peers if(response.Error != null) @@ -136,26 +138,10 @@ private EquihashJob CreateJob() job = CreateJob(); job.Init(blockTemplate, NextJobId(), - poolConfig, clusterConfig, clock, poolAddressDestination, network, - solver); + poolConfig, clusterConfig, clock, poolAddressDestination, network, solver); lock(jobLock) { - if(isNew) - { - if(via != null) - logger.Info(() => $"Detected new block {blockTemplate.Height} [{via}]"); - else - logger.Info(() => $"Detected new block {blockTemplate.Height}"); - - // update stats - BlockchainStats.LastNetworkBlockTime = clock.Now; - BlockchainStats.BlockHeight = blockTemplate.Height; - BlockchainStats.NetworkDifficulty = job.Difficulty; - BlockchainStats.NextNetworkTarget = blockTemplate.Target; - BlockchainStats.NextNetworkBits = blockTemplate.Bits; - } - validJobs.Insert(0, job); // trim active jobs @@ -163,6 +149,21 @@ private EquihashJob CreateJob() validJobs.RemoveAt(validJobs.Count - 1); } + if(isNew) + { + if(via != null) + logger.Info(() => $"Detected new block {blockTemplate.Height} [{via}]"); + else + logger.Info(() => $"Detected new block {blockTemplate.Height}"); + + // update stats + BlockchainStats.LastNetworkBlockTime = clock.Now; + BlockchainStats.BlockHeight = blockTemplate.Height; + BlockchainStats.NetworkDifficulty = job.Difficulty; + BlockchainStats.NextNetworkTarget = blockTemplate.Target; + BlockchainStats.NextNetworkBits = blockTemplate.Bits; + } + currentJob = job; } From 7bc6bbefa7f025a7e68125161f4cff88fcc88211 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 14 May 2019 09:59:29 +0200 Subject: [PATCH 155/178] WIP --- src/Miningcore/Mining/StatsRecorder.cs | 10 +++++++++ .../Model/Projections/MinerWorkerHashes.cs | 7 +++++++ .../Postgres/Repositories/StatsRepository.cs | 21 +++++++++++++++++++ .../Persistence/Postgres/Scripts/createdb.sql | 4 +++- .../Repositories/IStatsRepository.cs | 1 + 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/Miningcore/Mining/StatsRecorder.cs b/src/Miningcore/Mining/StatsRecorder.cs index 42f992939..d77a8f90f 100644 --- a/src/Miningcore/Mining/StatsRecorder.cs +++ b/src/Miningcore/Mining/StatsRecorder.cs @@ -163,6 +163,16 @@ private async Task UpdatePoolHashratesAsync() } } + else + { + // reset + pool.PoolStats.ConnectedMiners = 0; + pool.PoolStats.PoolHashrate = 0; + pool.PoolStats.SharesPerSecond = 0; + + messageBus.NotifyHashrateUpdated(pool.Config.Id, 0); + } + // persist await cf.RunTx(async (con, tx) => { diff --git a/src/Miningcore/Persistence/Model/Projections/MinerWorkerHashes.cs b/src/Miningcore/Persistence/Model/Projections/MinerWorkerHashes.cs index ba6b3eaa2..6811d893f 100644 --- a/src/Miningcore/Persistence/Model/Projections/MinerWorkerHashes.cs +++ b/src/Miningcore/Persistence/Model/Projections/MinerWorkerHashes.cs @@ -31,4 +31,11 @@ public class MinerWorkerHashes public DateTime FirstShare { get; set; } public DateTime LastShare { get; set; } } + + public class MinerWorkerHashrate + { + public string Miner { get; set; } + public string Worker { get; set; } + public double Hashrate { get; set; } + } } diff --git a/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs index 8a6edd5ac..8581b6553 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs @@ -195,6 +195,27 @@ public async Task GetMinerStatsAsync(IDbConnection con, IDbTransacti return result; } + public async Task GetPoolMinerWorkerHashratesAsync(IDbConnection con, IDbTransaction tx, string poolId) + { + logger.LogInvoke(); + + const string query = + "WITH cte AS " + + "( " + + " SELECT " + + " ROW_NUMBER() OVER(partition BY miner, worker ORDER BY created DESC) as rk, " + + " miner, worker " + + " FROM minerstats " + + " WHERE poolid = @poolId AND hashrate > 0 " + + ") " + + "SELECT miner, worker " + + "FROM cte " + + "WHERE rk = 1"; + + return (await con.QueryAsync(query, new { poolId })) + .ToArray(); + } + public async Task GetMinerPerformanceBetweenHourlyAsync(IDbConnection con, string poolId, string miner, DateTime start, DateTime end) { logger.LogInvoke(new[] { poolId }); diff --git a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql index 7f4ced3a0..9d0621480 100644 --- a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql +++ b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql @@ -1,4 +1,4 @@ -set role miningcore; +set role miningcore; CREATE TABLE shares ( @@ -107,5 +107,7 @@ CREATE TABLE minerstats CREATE INDEX IDX_MINERSTATS_POOL_CREATED on minerstats(poolid, created); CREATE INDEX IDX_MINERSTATS_POOL_MINER_CREATED on minerstats(poolid, miner, created); +CREATE INDEX IDX_MINERSTATS_POOL_MINER_CREATED_DESC on minerstats(miner, created desc); CREATE INDEX IDX_MINERSTATS_POOL_MINER_CREATED_HOUR on minerstats(poolid, miner, date_trunc('hour',created)); CREATE INDEX IDX_MINERSTATS_POOL_MINER_CREATED_DAY on minerstats(poolid, miner, date_trunc('day',created)); +CREATE INDEX IDX_MINERSTATS_POOL_MINER_WORKER_CREATED_HASHRATE on minerstats(poolid,miner,worker,created desc,hashrate); diff --git a/src/Miningcore/Persistence/Repositories/IStatsRepository.cs b/src/Miningcore/Persistence/Repositories/IStatsRepository.cs index f180b3825..0ece4162a 100644 --- a/src/Miningcore/Persistence/Repositories/IStatsRepository.cs +++ b/src/Miningcore/Persistence/Repositories/IStatsRepository.cs @@ -35,6 +35,7 @@ public interface IStatsRepository Task GetTotalPoolPaymentsAsync(IDbConnection con, string poolId); Task GetPoolPerformanceBetweenAsync(IDbConnection con, string poolId, SampleInterval interval, DateTime start, DateTime end); Task GetMinerStatsAsync(IDbConnection con, IDbTransaction tx, string poolId, string miner); + Task GetPoolMinerWorkerHashratesAsync(IDbConnection con, IDbTransaction tx, string poolId); Task PagePoolMinersByHashrateAsync(IDbConnection con, string poolId, DateTime from, int page, int pageSize); Task GetMinerPerformanceBetweenHourlyAsync(IDbConnection con, string poolId, string miner, DateTime start, DateTime end); Task GetMinerPerformanceBetweenDailyAsync(IDbConnection con, string poolId, string miner, DateTime start, DateTime end); From 084e10c86e64be4674d1257b43831a1a6b0cfbc8 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 14 May 2019 10:00:44 +0200 Subject: [PATCH 156/178] Cleanup --- src/Miningcore/Persistence/Postgres/Scripts/createdb.sql | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql index 9d0621480..18c9cf350 100644 --- a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql +++ b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql @@ -107,7 +107,6 @@ CREATE TABLE minerstats CREATE INDEX IDX_MINERSTATS_POOL_CREATED on minerstats(poolid, created); CREATE INDEX IDX_MINERSTATS_POOL_MINER_CREATED on minerstats(poolid, miner, created); -CREATE INDEX IDX_MINERSTATS_POOL_MINER_CREATED_DESC on minerstats(miner, created desc); CREATE INDEX IDX_MINERSTATS_POOL_MINER_CREATED_HOUR on minerstats(poolid, miner, date_trunc('hour',created)); CREATE INDEX IDX_MINERSTATS_POOL_MINER_CREATED_DAY on minerstats(poolid, miner, date_trunc('day',created)); CREATE INDEX IDX_MINERSTATS_POOL_MINER_WORKER_CREATED_HASHRATE on minerstats(poolid,miner,worker,created desc,hashrate); From 6102497d44f612716d2b56516b0aeaa6284ffb78 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 14 May 2019 11:47:13 +0200 Subject: [PATCH 157/178] Reset inactive pool, miner and worker hashrates. Fixes #262 --- src/Miningcore/Mining/StatsRecorder.cs | 49 +++++++++++++++++++ .../Postgres/Repositories/StatsRepository.cs | 2 +- .../Repositories/IStatsRepository.cs | 2 +- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/Miningcore/Mining/StatsRecorder.cs b/src/Miningcore/Mining/StatsRecorder.cs index d77a8f90f..28c8a3fd4 100644 --- a/src/Miningcore/Mining/StatsRecorder.cs +++ b/src/Miningcore/Mining/StatsRecorder.cs @@ -191,6 +191,22 @@ await cf.RunTx(async (con, tx) => if(result.Length == 0) continue; + // retrieve most recent miner/worker hashrate sample, if non-zero + var previousMinerWorkerHashrates = await cf.Run(async (con) => + { + return await statsRepo.GetPoolMinerWorkerHashratesAsync(con, poolId); + }); + + string buildKey(string miner, string worker = null) + { + return !string.IsNullOrEmpty(worker) ? $"{miner}:{worker}" : miner; + } + + var previousNonZeroMinerWorkers = new HashSet( + previousMinerWorkerHashrates.Select(x => buildKey(x.Miner, x.Worker))); + + var currentNonZeroMinerWorkers = new HashSet(); + // calculate & update miner, worker hashrates foreach(var minerHashes in byMiner) { @@ -200,6 +216,9 @@ await cf.RunTx(async (con, tx) => { stats.Miner = minerHashes.Key; + // book keeping + currentNonZeroMinerWorkers.Add(buildKey(stats.Miner)); + foreach(var item in minerHashes) { // calculate miner/worker stats @@ -218,13 +237,43 @@ await cf.RunTx(async (con, tx) => // persist await statsRepo.InsertMinerWorkerPerformanceStatsAsync(con, tx, stats); + // broadcast messageBus.NotifyHashrateUpdated(pool.Config.Id, hashrate, stats.Miner, item.Worker); + + // book keeping + currentNonZeroMinerWorkers.Add(buildKey(stats.Miner, stats.Worker)); } } }); messageBus.NotifyHashrateUpdated(pool.Config.Id, minerTotalHashrate, stats.Miner, null); } + + // identify and reset "orphaned" hashrates + var orphanedHashrateForMinerWorker = previousNonZeroMinerWorkers.Except(currentNonZeroMinerWorkers).ToArray(); + + await cf.RunTx(async (con, tx) => + { + // reset + stats.Hashrate = 0; + stats.SharesPerSecond = 0; + + foreach(var item in orphanedHashrateForMinerWorker) + { + var parts = item.Split(":"); + var miner = parts[0]; + var worker = parts.Length > 1 ? parts[1] : null; + + stats.Miner = parts[0]; + stats.Worker = worker; + + // persist + await statsRepo.InsertMinerWorkerPerformanceStatsAsync(con, tx, stats); + + // broadcast + messageBus.NotifyHashrateUpdated(pool.Config.Id, 0, stats.Miner, stats.Worker); + } + }); } } diff --git a/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs index 8581b6553..f02924f41 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs @@ -195,7 +195,7 @@ public async Task GetMinerStatsAsync(IDbConnection con, IDbTransacti return result; } - public async Task GetPoolMinerWorkerHashratesAsync(IDbConnection con, IDbTransaction tx, string poolId) + public async Task GetPoolMinerWorkerHashratesAsync(IDbConnection con, string poolId) { logger.LogInvoke(); diff --git a/src/Miningcore/Persistence/Repositories/IStatsRepository.cs b/src/Miningcore/Persistence/Repositories/IStatsRepository.cs index 0ece4162a..59b1f9c82 100644 --- a/src/Miningcore/Persistence/Repositories/IStatsRepository.cs +++ b/src/Miningcore/Persistence/Repositories/IStatsRepository.cs @@ -35,7 +35,7 @@ public interface IStatsRepository Task GetTotalPoolPaymentsAsync(IDbConnection con, string poolId); Task GetPoolPerformanceBetweenAsync(IDbConnection con, string poolId, SampleInterval interval, DateTime start, DateTime end); Task GetMinerStatsAsync(IDbConnection con, IDbTransaction tx, string poolId, string miner); - Task GetPoolMinerWorkerHashratesAsync(IDbConnection con, IDbTransaction tx, string poolId); + Task GetPoolMinerWorkerHashratesAsync(IDbConnection con, string poolId); Task PagePoolMinersByHashrateAsync(IDbConnection con, string poolId, DateTime from, int page, int pageSize); Task GetMinerPerformanceBetweenHourlyAsync(IDbConnection con, string poolId, string miner, DateTime start, DateTime end); Task GetMinerPerformanceBetweenDailyAsync(IDbConnection con, string poolId, string miner, DateTime start, DateTime end); From 0015a90bc584aeafe4763ac20e599e485e5da5df Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 14 May 2019 11:55:12 +0200 Subject: [PATCH 158/178] Some logging --- src/Miningcore/Mining/StatsRecorder.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Miningcore/Mining/StatsRecorder.cs b/src/Miningcore/Mining/StatsRecorder.cs index 28c8a3fd4..35a9e88dd 100644 --- a/src/Miningcore/Mining/StatsRecorder.cs +++ b/src/Miningcore/Mining/StatsRecorder.cs @@ -171,6 +171,8 @@ private async Task UpdatePoolHashratesAsync() pool.PoolStats.SharesPerSecond = 0; messageBus.NotifyHashrateUpdated(pool.Config.Id, 0); + + logger.Info(() => $"Reset performance stats for pool {poolId}"); } // persist @@ -272,6 +274,11 @@ await cf.RunTx(async (con, tx) => // broadcast messageBus.NotifyHashrateUpdated(pool.Config.Id, 0, stats.Miner, stats.Worker); + + if(string.IsNullOrEmpty(stats.Worker)) + logger.Info(() => $"Reset performance stats for miner {stats.Miner} on pool {poolId}"); + else + logger.Info(() => $"Reset performance stats for worker {stats.Worker} of miner {stats.Miner} on pool {poolId}"); } }); } From 3c0285d5cbf5a05695a28b79ef7718114a13dfaa Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 14 May 2019 12:23:11 +0200 Subject: [PATCH 159/178] Query fix --- .../Postgres/Repositories/StatsRepository.cs | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs index f02924f41..8fc404084 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs @@ -199,19 +199,23 @@ public async Task GetPoolMinerWorkerHashratesAsync(IDbCon { logger.LogInvoke(); - const string query = - "WITH cte AS " + - "( " + - " SELECT " + - " ROW_NUMBER() OVER(partition BY miner, worker ORDER BY created DESC) as rk, " + - " miner, worker " + - " FROM minerstats " + - " WHERE poolid = @poolId AND hashrate > 0 " + - ") " + - "SELECT miner, worker " + - "FROM cte " + - "WHERE rk = 1"; - + const string query = + "SELECT s.miner, s.worker, s.hashrate FROM " + + "(" + + " WITH cte AS" + + " (" + + " SELECT" + + " ROW_NUMBER() OVER (partition BY miner, worker ORDER BY created DESC) as rk," + + " miner, worker, hashrate" + + " FROM minerstats" + + " WHERE poolid = @poolId" + + " )" + + " SELECT miner, worker, hashrate" + + " FROM cte" + + " WHERE rk = 1" + + ") s" + + "WHERE s.hashrate > 0;"; + return (await con.QueryAsync(query, new { poolId })) .ToArray(); } From 9a644194500640c9f108d02d5e2d27785e799cda Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 14 May 2019 12:57:21 +0200 Subject: [PATCH 160/178] :( --- .../Persistence/Postgres/Repositories/StatsRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs index 8fc404084..e5e86bb72 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs @@ -213,7 +213,7 @@ public async Task GetPoolMinerWorkerHashratesAsync(IDbCon " SELECT miner, worker, hashrate" + " FROM cte" + " WHERE rk = 1" + - ") s" + + ") s " + "WHERE s.hashrate > 0;"; return (await con.QueryAsync(query, new { poolId })) From 5b44332b2540e69119edcf1539b5238e189f8535 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 15 May 2019 10:59:10 +0200 Subject: [PATCH 161/178] Add default pageSize for all API requests --- .../Api/Controllers/AdminApiController.cs | 5 +---- .../Api/Controllers/ClusterApiController.cs | 10 ++-------- .../Api/Controllers/PoolApiController.cs | 14 +++++++------- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/Miningcore/Api/Controllers/AdminApiController.cs b/src/Miningcore/Api/Controllers/AdminApiController.cs index 46c89128d..aa99b97a8 100644 --- a/src/Miningcore/Api/Controllers/AdminApiController.cs +++ b/src/Miningcore/Api/Controllers/AdminApiController.cs @@ -1,18 +1,15 @@ -using Autofac; +using Autofac; using Microsoft.AspNetCore.Mvc; using Miningcore.Api.Requests; using Miningcore.Api.Responses; using Miningcore.Configuration; using Miningcore.Extensions; -using Miningcore.JsonRpc; using Miningcore.Mining; using Miningcore.Persistence; using Miningcore.Persistence.Repositories; using Miningcore.Util; using System; using System.Collections.Concurrent; -using System.Linq; -using System.Net; using System.Threading.Tasks; namespace Miningcore.Api.Controllers diff --git a/src/Miningcore/Api/Controllers/ClusterApiController.cs b/src/Miningcore/Api/Controllers/ClusterApiController.cs index 6ea1bff9e..db2a1b9c2 100644 --- a/src/Miningcore/Api/Controllers/ClusterApiController.cs +++ b/src/Miningcore/Api/Controllers/ClusterApiController.cs @@ -1,24 +1,18 @@ -using Autofac; +using Autofac; using AutoMapper; using Microsoft.AspNetCore.Mvc; -using Miningcore.Api.Extensions; -using Miningcore.Api.Responses; using Miningcore.Blockchain; using Miningcore.Configuration; using Miningcore.Extensions; using Miningcore.Mining; using Miningcore.Persistence; using Miningcore.Persistence.Model; -using Miningcore.Persistence.Model.Projections; using Miningcore.Persistence.Repositories; using Miningcore.Time; -using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Data; using System.Globalization; using System.Linq; -using System.Net; using System.Threading.Tasks; namespace Miningcore.Api.Controllers @@ -54,7 +48,7 @@ public ClusterApiController(IComponentContext ctx) [HttpGet("blocks")] public async Task PageBlocksPagedAsync( - [FromQuery] int page, [FromQuery] int pageSize, [FromQuery] BlockStatus[] state) + [FromQuery] int page, [FromQuery] int pageSize = 15, [FromQuery] BlockStatus[] state = null) { var blockStates = state != null && state.Length > 0 ? state : diff --git a/src/Miningcore/Api/Controllers/PoolApiController.cs b/src/Miningcore/Api/Controllers/PoolApiController.cs index 7ca71be4a..8dca34544 100644 --- a/src/Miningcore/Api/Controllers/PoolApiController.cs +++ b/src/Miningcore/Api/Controllers/PoolApiController.cs @@ -1,4 +1,4 @@ -using Autofac; +using Autofac; using AutoMapper; using Microsoft.AspNetCore.Mvc; using Miningcore.Api.Extensions; @@ -148,7 +148,7 @@ public async Task GetPoolPerformanceAsync(string poolId, [HttpGet("{poolId}/miners")] public async Task PagePoolMinersAsync( - string poolId, [FromQuery] int page, [FromQuery] int pageSize) + string poolId, [FromQuery] int page, [FromQuery] int pageSize = 15) { var pool = GetPool(poolId); @@ -166,7 +166,7 @@ public async Task PagePoolMinersAsync( [HttpGet("{poolId}/blocks")] public async Task PagePoolBlocksPagedAsync( - string poolId, [FromQuery] int page, [FromQuery] int pageSize, [FromQuery] BlockStatus[] state) + string poolId, [FromQuery] int page, [FromQuery] int pageSize = 15, [FromQuery] BlockStatus[] state = null) { var pool = GetPool(poolId); @@ -203,7 +203,7 @@ public async Task PagePoolMinersAsync( [HttpGet("{poolId}/payments")] public async Task PagePoolPaymentsAsync( - string poolId, [FromQuery] int page, [FromQuery] int pageSize) + string poolId, [FromQuery] int page, [FromQuery] int pageSize = 15) { var pool = GetPool(poolId); @@ -268,7 +268,7 @@ public async Task PagePoolMinersAsync( [HttpGet("{poolId}/miners/{address}/payments")] public async Task PageMinerPaymentsAsync( - string poolId, string address, [FromQuery] int page, [FromQuery] int pageSize) + string poolId, string address, [FromQuery] int page, [FromQuery] int pageSize = 15) { var pool = GetPool(poolId); @@ -300,7 +300,7 @@ public async Task PagePoolMinersAsync( [HttpGet("{poolId}/miners/{address}/balancechanges")] public async Task PageMinerBalanceChangesAsync( - string poolId, string address, [FromQuery] int page, [FromQuery] int pageSize) + string poolId, string address, [FromQuery] int page, [FromQuery] int pageSize = 15) { var pool = GetPool(poolId); @@ -317,7 +317,7 @@ public async Task PagePoolMinersAsync( [HttpGet("{poolId}/miners/{address}/earnings/daily")] public async Task PageMinerEarningsByDayAsync( - string poolId, string address, [FromQuery] int page, [FromQuery] int pageSize) + string poolId, string address, [FromQuery] int page, [FromQuery] int pageSize = 15) { var pool = GetPool(poolId); From f5276cab47c5e70c0f961ccceb567b84531fa034 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 15 May 2019 11:01:03 +0200 Subject: [PATCH 162/178] Bump FluentValidation from 8.3.0 to 8.4.0 in /src/Miningcore (#626) Bumps [FluentValidation](https://github.com/JeremySkinner/fluentvalidation) from 8.3.0 to 8.4.0. - [Release notes](https://github.com/JeremySkinner/fluentvalidation/releases) - [Changelog](https://github.com/JeremySkinner/FluentValidation/blob/master/Changelog.txt) - [Commits](https://github.com/JeremySkinner/fluentvalidation/compare/8.3.0...8.4.0) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 1d918ef0b..187eb32e0 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -54,7 +54,7 @@ - + From 1bcd949d43b118ee68f426ee10e6e3aa8a1846bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 15 May 2019 11:02:27 +0200 Subject: [PATCH 163/178] Bump NBitcoin from 4.1.2.12 to 4.1.2.22 in /src/Miningcore (#625) Bumps [NBitcoin](https://github.com/MetacoSA/NBitcoin) from 4.1.2.12 to 4.1.2.22. - [Release notes](https://github.com/MetacoSA/NBitcoin/releases) - [Commits](https://github.com/MetacoSA/NBitcoin/compare/v4.1.2.12...v4.1.2.22) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 187eb32e0..e8d502b46 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -63,7 +63,7 @@ - + From e00997b916e35f70eb9b00141f044fbdbd4c816b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 15 May 2019 11:02:51 +0200 Subject: [PATCH 164/178] Bump NLog.Extensions.Logging from 1.4.0 to 1.5.0 in /src/Miningcore (#624) Bumps [NLog.Extensions.Logging](https://github.com/NLog/NLog.Extensions.Logging) from 1.4.0 to 1.5.0. - [Release notes](https://github.com/NLog/NLog.Extensions.Logging/releases) - [Changelog](https://github.com/NLog/NLog.Extensions.Logging/blob/master/CHANGELOG.MD) - [Commits](https://github.com/NLog/NLog.Extensions.Logging/compare/v1.4.0...v1.5.0) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index e8d502b46..f6a0bb529 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -67,7 +67,7 @@ - + From ed69a5bcb3fd5b9ead26d5a3cd1eab705588c037 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 15 May 2019 11:03:09 +0200 Subject: [PATCH 165/178] Bump AspNetCoreRateLimit from 3.0.3 to 3.0.4 in /src/Miningcore (#622) Bumps [AspNetCoreRateLimit](https://github.com/stefanprodan/AspNetCoreRateLimit) from 3.0.3 to 3.0.4. - [Release notes](https://github.com/stefanprodan/AspNetCoreRateLimit/releases) - [Commits](https://github.com/stefanprodan/AspNetCoreRateLimit/commits) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index f6a0bb529..b246e3207 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -49,7 +49,7 @@
- + From d181c69546fe4d1dc0910205b53b2029ebc315b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 15 May 2019 11:03:28 +0200 Subject: [PATCH 166/178] Bump FluentValidation.ValidatorAttribute in /src/Miningcore (#623) Bumps [FluentValidation.ValidatorAttribute](https://github.com/JeremySkinner/fluentvalidation) from 8.3.0 to 8.4.0. - [Release notes](https://github.com/JeremySkinner/fluentvalidation/releases) - [Changelog](https://github.com/JeremySkinner/FluentValidation/blob/master/Changelog.txt) - [Commits](https://github.com/JeremySkinner/fluentvalidation/compare/8.3.0...8.4.0) Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index b246e3207..7f46795d5 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -53,7 +53,7 @@ - + From d9a8eae329680f443683f2d60a4f4241d54901f0 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Wed, 15 May 2019 13:52:11 +0200 Subject: [PATCH 167/178] Use case-insensitive string comparison for ethereum wallets. Fixes #577 --- src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs index 660ba0954..139b4764b 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs @@ -149,7 +149,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); // is it block mined by us? - if(blockInfo.Miner == poolConfig.Address) + if(string.Equals(blockInfo.Miner, poolConfig.Address, StringComparison.OrdinalIgnoreCase)) { // additional check // NOTE: removal of first character of both sealfields caused by @@ -211,7 +211,7 @@ public async Task ClassifyBlocksAsync(Block[] blocks) var uncle = uncleResponses.Where(x => x.Error == null && x.Response != null) .Select(x => x.Response.ToObject()) - .FirstOrDefault(x => x.Miner == poolConfig.Address); + .FirstOrDefault(x => string.Equals(x.Miner, poolConfig.Address, StringComparison.OrdinalIgnoreCase)); if(uncle != null) { From 834e5297c8d36bb4885038ab22b0142479e378f6 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sun, 19 May 2019 23:55:53 +0200 Subject: [PATCH 168/178] CanonicalName --- src/Miningcore/Configuration/ClusterConfig.cs | 6 ++++++ src/Miningcore/coins.json | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index 9d9226e32..64a85f50f 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -54,6 +54,12 @@ public abstract partial class CoinTemplate [JsonProperty(Order = -10)] public string Name { get; set; } + /// + /// Canonical Name + /// + [JsonProperty(Order = -10)] + public string CanonicalName { get; set; } + /// /// Trade Symbol /// diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index 353c7ba42..e6ab15cff 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -451,6 +451,7 @@ }, "digibyte-sha256": { "name": "Digibyte-Sha256", + "canonicalName": "Digibyte", "symbol": "DGB", "family": "bitcoin", "coinbaseHasher": { @@ -489,6 +490,7 @@ }, "digibyte-skein": { "name": "Digibyte-Skein", + "canonicalName": "Digibyte", "symbol": "DGB", "family": "bitcoin", "coinbaseHasher": { @@ -525,6 +527,7 @@ }, "digibyte-groestl": { "name": "Digibyte-Groestl", + "canonicalName": "Digibyte", "symbol": "DGB", "family": "bitcoin", "coinbaseHasher": { @@ -544,6 +547,7 @@ }, "digibyte-odo": { "name": "Digibyte-Odo", + "canonicalName": "Digibyte", "symbol": "DGB", "family": "bitcoin", "coinbaseHasher": { @@ -574,6 +578,7 @@ }, "verge-lyra": { "name": "Verge-Lyra", + "canonicalName": "Verge", "symbol": "XVG", "family": "bitcoin", "coinbaseHasher": { @@ -598,6 +603,7 @@ }, "verge-scrypt": { "name": "Verge-Scrypt", + "canonicalName": "Verge", "symbol": "XVG", "family": "bitcoin", "coinbaseHasher": { @@ -623,6 +629,7 @@ }, "verge-x17": { "name": "Verge-X17", + "canonicalName": "Verge", "symbol": "XVG", "family": "bitcoin", "coinbaseHasher": { @@ -646,6 +653,7 @@ }, "verge-blake": { "name": "Verge-Blake", + "canonicalName": "Verge", "symbol": "XVG", "family": "bitcoin", "coinbaseHasher": { @@ -669,6 +677,7 @@ }, "verge-groestl": { "name": "Verge-Groestl", + "canonicalName": "Verge", "symbol": "XVG", "family": "bitcoin", "coinbaseHasher": { From d67837048672fad5b050df9ab95d984da9338c2f Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Sun, 19 May 2019 23:57:29 +0200 Subject: [PATCH 169/178] WIP --- src/Miningcore/Api/Responses/GetPoolsResponse.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Miningcore/Api/Responses/GetPoolsResponse.cs b/src/Miningcore/Api/Responses/GetPoolsResponse.cs index 8d411a13b..99e4c2e44 100644 --- a/src/Miningcore/Api/Responses/GetPoolsResponse.cs +++ b/src/Miningcore/Api/Responses/GetPoolsResponse.cs @@ -31,6 +31,7 @@ public class ApiCoinConfig { public string Type { get; set; } public string Name { get; set; } + public string CanonicalName { get; set; } public string Family { get; set; } public string Algorithm { get; set; } } From 2f348d46608a8df41bb23f6dfbdc5c463ab19bce Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 20 May 2019 00:03:04 +0200 Subject: [PATCH 170/178] WIP --- src/Miningcore/Configuration/ClusterConfig.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index 64a85f50f..3771c2cb1 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -57,7 +57,6 @@ public abstract partial class CoinTemplate /// /// Canonical Name /// - [JsonProperty(Order = -10)] public string CanonicalName { get; set; } /// From dd8413db096ea60ee194b6eca66b991fe175d682 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 20 May 2019 00:04:48 +0200 Subject: [PATCH 171/178] WIP --- src/Miningcore/Api/Responses/GetPoolsResponse.cs | 4 +++- src/Miningcore/Configuration/ClusterConfig.cs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Miningcore/Api/Responses/GetPoolsResponse.cs b/src/Miningcore/Api/Responses/GetPoolsResponse.cs index 99e4c2e44..f72c1b486 100644 --- a/src/Miningcore/Api/Responses/GetPoolsResponse.cs +++ b/src/Miningcore/Api/Responses/GetPoolsResponse.cs @@ -31,9 +31,11 @@ public class ApiCoinConfig { public string Type { get; set; } public string Name { get; set; } - public string CanonicalName { get; set; } public string Family { get; set; } public string Algorithm { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string CanonicalName { get; set; } } public class ApiPoolPaymentProcessingConfig diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index 3771c2cb1..96f5c8266 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -57,6 +57,7 @@ public abstract partial class CoinTemplate /// /// Canonical Name /// + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string CanonicalName { get; set; } /// From 7ce806a5812134202bdfe3b6a82b9f41e8c8cf48 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 20 May 2019 00:08:44 +0200 Subject: [PATCH 172/178] WIP --- src/Miningcore/coins.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index e6ab15cff..6701fb117 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -470,6 +470,7 @@ }, "digibyte-scrypt": { "name": "Digibyte-Scrypt", + "canonicalName": "Digibyte", "symbol": "DGB", "family": "bitcoin", "coinbaseHasher": { @@ -509,6 +510,7 @@ }, "digibyte-qubit": { "name": "Digibyte-Qubit", + "canonicalName": "Digibyte", "symbol": "DGB", "family": "bitcoin", "coinbaseHasher": { From 64b2be980d12b02305e893751d6a7d9ea77cb9a5 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 20 May 2019 16:02:07 +0200 Subject: [PATCH 173/178] X25x hash --- libs/runtimes/win-x64/libmultihash.dll | Bin 1200640 -> 1350656 bytes src/Miningcore.Tests/Crypto/HashingTests.cs | 11 + .../Crypto/Hashing/Algorithms/X25x.cs | 42 + src/Miningcore/Native/LibMultihash.cs | 3 + src/Native/libmultihash/Makefile | 6 +- src/Native/libmultihash/exports.cpp | 6 + src/Native/libmultihash/lane.c | 2151 +++++++++++++++++ src/Native/libmultihash/lane.h | 56 + src/Native/libmultihash/libmultihash.vcxproj | 6 + .../libmultihash/libmultihash.vcxproj.filters | 18 + src/Native/libmultihash/sha3/panama.c | 334 +++ src/Native/libmultihash/sha3/sph_panama.h | 126 + src/Native/libmultihash/x25x.c | 182 ++ src/Native/libmultihash/x25x.h | 16 + 14 files changed, 2954 insertions(+), 3 deletions(-) create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/X25x.cs create mode 100644 src/Native/libmultihash/lane.c create mode 100644 src/Native/libmultihash/lane.h create mode 100644 src/Native/libmultihash/sha3/panama.c create mode 100644 src/Native/libmultihash/sha3/sph_panama.h create mode 100644 src/Native/libmultihash/x25x.c create mode 100644 src/Native/libmultihash/x25x.h diff --git a/libs/runtimes/win-x64/libmultihash.dll b/libs/runtimes/win-x64/libmultihash.dll index fac20143d4430f5d808e22618a6ffd4db5578045..f141fc95e1471c8f10e8d77c8baca229afaed2bc 100644 GIT binary patch delta 328334 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 TtYk55bV6#K3$y+YVs(b1 diff --git a/src/Miningcore.Tests/Crypto/HashingTests.cs b/src/Miningcore.Tests/Crypto/HashingTests.cs index cc1b7f269..f311cf8d7 100644 --- a/src/Miningcore.Tests/Crypto/HashingTests.cs +++ b/src/Miningcore.Tests/Crypto/HashingTests.cs @@ -233,6 +233,17 @@ public void X21S_Hash() Assert.Equal("0bfd2e20a3656b5f92079ea5c6485223b00344f9f1005ab9ecedff3c42ccf76f", result); } + [Fact] + public void X25X_Hash() + { + var hasher = new X25X(); + var hash = new byte[32]; + hasher.Digest(testValue, hash); + var result = hash.ToHexString(); + + Assert.Equal("fe2a3d0e45eb5afbf007055c2605590db4167169dc03d1d5a070885771e51846", result); + } + [Fact] public void Odocrypt_Hash() { diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/X25x.cs b/src/Miningcore/Crypto/Hashing/Algorithms/X25x.cs new file mode 100644 index 000000000..8d7ae655f --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/X25x.cs @@ -0,0 +1,42 @@ +/* +Copyright 2017 Coin Foundry (coinfoundry.org) +Authors: Oliver Weichhold (oliver@weichhold.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +using System; +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms +{ + public unsafe class X25X : IHashAlgorithm + { + public void Digest(ReadOnlySpan data, Span result, params object[] extra) + { + Contract.Requires(result.Length >= 32, $"{nameof(result)} must be greater or equal 32 bytes"); + + fixed (byte* input = data) + { + fixed (byte* output = result) + { + LibMultihash.x25x(input, output, (uint) data.Length); + } + } + } + } +} diff --git a/src/Miningcore/Native/LibMultihash.cs b/src/Miningcore/Native/LibMultihash.cs index 81b20d948..cc452b8c5 100644 --- a/src/Miningcore/Native/LibMultihash.cs +++ b/src/Miningcore/Native/LibMultihash.cs @@ -49,6 +49,9 @@ public static unsafe class LibMultihash [DllImport("libmultihash", EntryPoint = "x21s_export", CallingConvention = CallingConvention.Cdecl)] public static extern int x21s(byte* input, void* output, uint inputLength); + [DllImport("libmultihash", EntryPoint = "x25x_export", CallingConvention = CallingConvention.Cdecl)] + public static extern int x25x(byte* input, void* output, uint inputLength); + [DllImport("libmultihash", EntryPoint = "odocrypt_export", CallingConvention = CallingConvention.Cdecl)] public static extern int odocrypt(byte* input, void* output, uint inputLength, uint key); diff --git a/src/Native/libmultihash/Makefile b/src/Native/libmultihash/Makefile index acb01562d..0c1a2e268 100644 --- a/src/Native/libmultihash/Makefile +++ b/src/Native/libmultihash/Makefile @@ -5,14 +5,14 @@ LDFLAGS = -shared LDLIBS = -lsodium TARGET = libmultihash.so -OBJECTS = bcrypt.o blake.o blake2s.o c11.o dcrypt.o fresh.o \ +OBJECTS = bcrypt.o blake.o blake2s.o c11.o dcrypt.o fresh.o lane.o \ fugue.o groestl.o hefty1.o jh.o keccak.o neoscrypt.o exports.o nist5.o quark.o qubit.o s3.o scryptn.o \ sha3/aes_helper.o sha3/hamsi.o sha3/hamsi_helper.o sha3/sph_blake.o sha3/sph_bmw.o sha3/sph_cubehash.o \ sha3/sph_echo.o sha3/sph_fugue.o sha3/sph_groestl.o sha3/sph_hefty1.o sha3/sph_jh.o sha3/sph_keccak.o \ sha3/sph_luffa.o sha3/sph_shabal.o sha3/sph_shavite.o sha3/sph_simd.o sha3/sph_skein.o sha3/sph_whirlpool.o \ - sha3/sph_haval.o sha3/sph_sha2.o sha3/sph_sha2big.o sha3/sph_blake2s.o sha3/sm3.o \ + sha3/sph_haval.o sha3/sph_sha2.o sha3/sph_sha2big.o sha3/sph_blake2s.o sha3/sm3.o sha3/panama.o \ sha3/extra.o sha3/gost_streebog.o sha3/sph_tiger.o sha3/SWIFFTX.o KeccakP-800-reference.o \ - shavite3.o skein.o x11.o x13.o x15.o x17.o x16r.o x16s.o x21s.o odocrypt.o \ + shavite3.o skein.o x11.o x13.o x15.o x17.o x16r.o x16s.o x21s.o odocrypt.o x25x.o \ Lyra2.o Lyra2RE.o Sponge.o geek.o \ equi/util.o equi/support/cleanse.o equi/random.o \ equi/uint256.o equi/arith_uint256.o equi/crypto/hmac_sha512.o \ diff --git a/src/Native/libmultihash/exports.cpp b/src/Native/libmultihash/exports.cpp index 2feac7b64..02194b73f 100644 --- a/src/Native/libmultihash/exports.cpp +++ b/src/Native/libmultihash/exports.cpp @@ -46,6 +46,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "x16r.h" #include "x16s.h" #include "x21s.h" +#include "x25x.h" #include "hashodo.h" #include "equi/equihashverify.h" #include "libethash/sha3.h" @@ -222,6 +223,11 @@ extern "C" MODULE_API void x21s_export(const char* input, char* output, uint32_t x21s_hash(input, output, input_len); } +extern "C" MODULE_API void x25x_export(const char* input, char* output, uint32_t input_len) +{ + x25x_hash(input, output, input_len); +} + extern "C" MODULE_API void odocrypt_export(const char* input, char* output, uint32_t input_len, uint32_t key) { odocrypt_hash(input, output, input_len, key); diff --git a/src/Native/libmultihash/lane.c b/src/Native/libmultihash/lane.c new file mode 100644 index 000000000..ee2cd0576 --- /dev/null +++ b/src/Native/libmultihash/lane.c @@ -0,0 +1,2151 @@ +/* + * Copyright (c) 2008 Sebastiaan Indesteege + * + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Optimised ANSI-C implementation of LANE + */ + +#include "lane.h" + +#define T8(x) ((x) & 0xff) +#define B0(x) (T8((x) )) +#define B1(x) (T8((x) >> 8)) +#define B2(x) (T8((x) >> 16)) +#define B3(x) (T8((x) >> 24)) +#define MSB32(x) ((u32)((((u64)(x))>>32) & 0xffffffff)) +#define LSB32(x) ((u32)((((u64)(x)) ) & 0xffffffff)) +#ifdef LANE_BIG_ENDIAN +#define U8TO32_BIG(c) (((u32*)(c))[0]) +#define U32TO8_BIG(c, v) ((u32*)(c))[0]=v +#else +#define U8TO32_BIG(c) (((u32)T8(*((u8*)(c))) << 24) | \ + ((u32)T8(*(((u8*)(c)) + 1)) << 16) | \ + ((u32)T8(*(((u8*)(c)) + 2)) << 8) | \ + ((u32)T8(*(((u8*)(c)) + 3)))) +#define U32TO8_BIG(c, v) do { \ + u32 tmp_portable_h_x = (v); \ + u8 *tmp_portable_h_d = (c); \ + tmp_portable_h_d[0] = T8(tmp_portable_h_x >> 24); \ + tmp_portable_h_d[1] = T8(tmp_portable_h_x >> 16); \ + tmp_portable_h_d[2] = T8(tmp_portable_h_x >> 8); \ + tmp_portable_h_d[3] = T8(tmp_portable_h_x); \ + } while (0) +#endif /* LANE_BIG_ENDIAN */ + +static const u32 iv224[8] = { + 0xc8245a86U, 0x8d733102U, 0x314ddcb9U, 0xf60a7ef4U, + 0x57b8c917U, 0xeefeaec2U, 0xff4fc3beU, 0x87c4728eU +}; + +static const u32 iv256[8] = { + 0xbe292e17U, 0xbb541ff2U, 0xfe54b6f7U, 0x30b1c96aU, + 0x7b259268U, 0x8539bdf3U, 0x97c4bdd6U, 0x49763fb8U +}; + +static const u32 iv384[16] = { + 0x148922ceU, 0x548c3001U, 0x76978bc8U, 0x266e008cU, + 0x3dc60765U, 0xd85b09d9U, 0x4cb1c8d8U, 0xe2cab952U, + 0xdb72be8eU, 0x685f0783U, 0xfa436c3dU, 0x4b9acb90U, + 0x5088dd47U, 0x932f55a9U, 0xa0c415c6U, 0xdb6dd795U +}; + +static const u32 iv512[16] = { + 0x9b603481U, 0x1d5a931bU, 0x69c4e6e0U, 0x975e2681U, + 0xb863ba53U, 0x8d1be11bU, 0x77340080U, 0xd42c48a5U, + 0x3a3a1d61U, 0x1cf3a1c4U, 0xf0a30347U, 0x7e56a44aU, + 0x9530ee60U, 0xdadb05b6U, 0x3ae3ac7cU, 0xd732ac6aU +}; + +static const u32 T0[256] = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; +static const u32 T1[256] = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}; +static const u32 T2[256] = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}; +static const u32 T3[256] = { + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}; + +static const u32 C[768] = { + 0x07fc703d, 0xd3fe381f, 0xb9ff1c0e, 0x5cff8e07, 0xfe7fc702, 0x7f3fe381, 0xef9ff1c1, 0xa7cff8e1, + 0x83e7fc71, 0x91f3fe39, 0x98f9ff1d, 0x9c7cff8f, 0x9e3e7fc6, 0x4f1f3fe3, 0xf78f9ff0, 0x7bc7cff8, + 0x3de3e7fc, 0x1ef1f3fe, 0x0f78f9ff, 0xd7bc7cfe, 0x6bde3e7f, 0xe5ef1f3e, 0x72f78f9f, 0xe97bc7ce, + 0x74bde3e7, 0xea5ef1f2, 0x752f78f9, 0xea97bc7d, 0xa54bde3f, 0x82a5ef1e, 0x4152f78f, 0xf0a97bc6, + 0x7854bde3, 0xec2a5ef0, 0x76152f78, 0x3b0a97bc, 0x1d854bde, 0x0ec2a5ef, 0xd76152f6, 0x6bb0a97b, + 0xe5d854bc, 0x72ec2a5e, 0x3976152f, 0xccbb0a96, 0x665d854b, 0xe32ec2a4, 0x71976152, 0x38cbb0a9, + 0xcc65d855, 0xb632ec2b, 0x8b197614, 0x458cbb0a, 0x22c65d85, 0xc1632ec3, 0xb0b19760, 0x5858cbb0, + 0x2c2c65d8, 0x161632ec, 0x0b0b1976, 0x05858cbb, 0xd2c2c65c, 0x6961632e, 0x34b0b197, 0xca5858ca, + 0x652c2c65, 0xe2961633, 0xa14b0b18, 0x50a5858c, 0x2852c2c6, 0x14296163, 0xda14b0b0, 0x6d0a5858, + 0x36852c2c, 0x1b429616, 0x0da14b0b, 0xd6d0a584, 0x6b6852c2, 0x35b42961, 0xcada14b1, 0xb56d0a59, + 0x8ab6852d, 0x955b4297, 0x9aada14a, 0x4d56d0a5, 0xf6ab6853, 0xab55b428, 0x55aada14, 0x2ad56d0a, + 0x156ab685, 0xdab55b43, 0xbd5aada0, 0x5ead56d0, 0x2f56ab68, 0x17ab55b4, 0x0bd5aada, 0x05ead56d, + 0xd2f56ab7, 0xb97ab55a, 0x5cbd5aad, 0xfe5ead57, 0xaf2f56aa, 0x5797ab55, 0xfbcbd5ab, 0xade5ead4, + 0x56f2f56a, 0x2b797ab5, 0xc5bcbd5b, 0xb2de5eac, 0x596f2f56, 0x2cb797ab, 0xc65bcbd4, 0x632de5ea, + 0x3196f2f5, 0xc8cb797b, 0xb465bcbc, 0x5a32de5e, 0x2d196f2f, 0xc68cb796, 0x63465bcb, 0xe1a32de4, + 0x70d196f2, 0x3868cb79, 0xcc3465bd, 0xb61a32df, 0x8b0d196e, 0x45868cb7, 0xf2c3465a, 0x7961a32d, + 0xecb0d197, 0xa65868ca, 0x532c3465, 0xf9961a33, 0xaccb0d18, 0x5665868c, 0x2b32c346, 0x159961a3, + 0xdaccb0d0, 0x6d665868, 0x36b32c34, 0x1b59961a, 0x0daccb0d, 0xd6d66587, 0xbb6b32c2, 0x5db59961, + 0xfedaccb1, 0xaf6d6659, 0x87b6b32d, 0x93db5997, 0x99edacca, 0x4cf6d665, 0xf67b6b33, 0xab3db598, + 0x559edacc, 0x2acf6d66, 0x1567b6b3, 0xdab3db58, 0x6d59edac, 0x36acf6d6, 0x1b567b6b, 0xddab3db4, + 0x6ed59eda, 0x376acf6d, 0xcbb567b7, 0xb5dab3da, 0x5aed59ed, 0xfd76acf7, 0xaebb567a, 0x575dab3d, + 0xfbaed59f, 0xadd76ace, 0x56ebb567, 0xfb75dab2, 0x7dbaed59, 0xeedd76ad, 0xa76ebb57, 0x83b75daa, + 0x41dbaed5, 0xf0edd76b, 0xa876ebb4, 0x543b75da, 0x2a1dbaed, 0xc50edd77, 0xb2876eba, 0x5943b75d, + 0xfca1dbaf, 0xae50edd6, 0x572876eb, 0xfb943b74, 0x7dca1dba, 0x3ee50edd, 0xcf72876f, 0xb7b943b6, + 0x5bdca1db, 0xfdee50ec, 0x7ef72876, 0x3f7b943b, 0xcfbdca1c, 0x67dee50e, 0x33ef7287, 0xc9f7b942, + 0x64fbdca1, 0xe27dee51, 0xa13ef729, 0x809f7b95, 0x904fbdcb, 0x9827dee4, 0x4c13ef72, 0x2609f7b9, + 0xc304fbdd, 0xb1827def, 0x88c13ef6, 0x44609f7b, 0xf2304fbc, 0x791827de, 0x3c8c13ef, 0xce4609f6, + 0x672304fb, 0xe391827c, 0x71c8c13e, 0x38e4609f, 0xcc72304e, 0x66391827, 0xe31c8c12, 0x718e4609, + 0xe8c72305, 0xa4639183, 0x8231c8c0, 0x4118e460, 0x208c7230, 0x10463918, 0x08231c8c, 0x04118e46, + 0x0208c723, 0xd1046390, 0x688231c8, 0x344118e4, 0x1a208c72, 0x0d104639, 0xd688231d, 0xbb44118f, + 0x8da208c6, 0x46d10463, 0xf3688230, 0x79b44118, 0x3cda208c, 0x1e6d1046, 0x0f368823, 0xd79b4410, + 0x6bcda208, 0x35e6d104, 0x1af36882, 0x0d79b441, 0xd6bcda21, 0xbb5e6d11, 0x8daf3689, 0x96d79b45, + 0x9b6bcda3, 0x9db5e6d0, 0x4edaf368, 0x276d79b4, 0x13b6bcda, 0x09db5e6d, 0xd4edaf37, 0xba76d79a, + 0x5d3b6bcd, 0xfe9db5e7, 0xaf4edaf2, 0x57a76d79, 0xfbd3b6bd, 0xade9db5f, 0x86f4edae, 0x437a76d7, + 0xf1bd3b6a, 0x78de9db5, 0xec6f4edb, 0xa637a76c, 0x531bd3b6, 0x298de9db, 0xc4c6f4ec, 0x62637a76, + 0x3131bd3b, 0xc898de9c, 0x644c6f4e, 0x322637a7, 0xc9131bd2, 0x64898de9, 0xe244c6f5, 0xa122637b, + 0x809131bc, 0x404898de, 0x20244c6f, 0xc0122636, 0x6009131b, 0xe004898c, 0x700244c6, 0x38012263, + 0xcc009130, 0x66004898, 0x3300244c, 0x19801226, 0x0cc00913, 0xd6600488, 0x6b300244, 0x35980122, + 0x1acc0091, 0xdd660049, 0xbeb30025, 0x8f598013, 0x97acc008, 0x4bd66004, 0x25eb3002, 0x12f59801, + 0xd97acc01, 0xbcbd6601, 0x8e5eb301, 0x972f5981, 0x9b97acc1, 0x9dcbd661, 0x9ee5eb31, 0x9f72f599, + 0x9fb97acd, 0x9fdcbd67, 0x9fee5eb2, 0x4ff72f59, 0xf7fb97ad, 0xabfdcbd7, 0x85fee5ea, 0x42ff72f5, + 0xf17fb97b, 0xa8bfdcbc, 0x545fee5e, 0x2a2ff72f, 0xc517fb96, 0x628bfdcb, 0xe145fee4, 0x70a2ff72, + 0x38517fb9, 0xcc28bfdd, 0xb6145fef, 0x8b0a2ff6, 0x458517fb, 0xf2c28bfc, 0x796145fe, 0x3cb0a2ff, + 0xce58517e, 0x672c28bf, 0xe396145e, 0x71cb0a2f, 0xe8e58516, 0x7472c28b, 0xea396144, 0x751cb0a2, + 0x3a8e5851, 0xcd472c29, 0xb6a39615, 0x8b51cb0b, 0x95a8e584, 0x4ad472c2, 0x256a3961, 0xc2b51cb1, + 0xb15a8e59, 0x88ad472d, 0x9456a397, 0x9a2b51ca, 0x4d15a8e5, 0xf68ad473, 0xab456a38, 0x55a2b51c, + 0x2ad15a8e, 0x1568ad47, 0xdab456a2, 0x6d5a2b51, 0xe6ad15a9, 0xa3568ad5, 0x81ab456b, 0x90d5a2b4, + 0x486ad15a, 0x243568ad, 0xc21ab457, 0xb10d5a2a, 0x5886ad15, 0xfc43568b, 0xae21ab44, 0x5710d5a2, + 0x2b886ad1, 0xc5c43569, 0xb2e21ab5, 0x89710d5b, 0x94b886ac, 0x4a5c4356, 0x252e21ab, 0xc29710d4, + 0x614b886a, 0x30a5c435, 0xc852e21b, 0xb429710c, 0x5a14b886, 0x2d0a5c43, 0xc6852e20, 0x63429710, + 0x31a14b88, 0x18d0a5c4, 0x0c6852e2, 0x06342971, 0xd31a14b9, 0xb98d0a5d, 0x8cc6852f, 0x96634296, + 0x4b31a14b, 0xf598d0a4, 0x7acc6852, 0x3d663429, 0xceb31a15, 0xb7598d0b, 0x8bacc684, 0x45d66342, + 0x22eb31a1, 0xc17598d1, 0xb0bacc69, 0x885d6635, 0x942eb31b, 0x9a17598c, 0x4d0bacc6, 0x2685d663, + 0xc342eb30, 0x61a17598, 0x30d0bacc, 0x18685d66, 0x0c342eb3, 0xd61a1758, 0x6b0d0bac, 0x358685d6, + 0x1ac342eb, 0xdd61a174, 0x6eb0d0ba, 0x3758685d, 0xcbac342f, 0xb5d61a16, 0x5aeb0d0b, 0xfd758684, + 0x7ebac342, 0x3f5d61a1, 0xcfaeb0d1, 0xb7d75869, 0x8bebac35, 0x95f5d61b, 0x9afaeb0c, 0x4d7d7586, + 0x26bebac3, 0xc35f5d60, 0x61afaeb0, 0x30d7d758, 0x186bebac, 0x0c35f5d6, 0x061afaeb, 0xd30d7d74, + 0x6986beba, 0x34c35f5d, 0xca61afaf, 0xb530d7d6, 0x5a986beb, 0xfd4c35f4, 0x7ea61afa, 0x3f530d7d, + 0xcfa986bf, 0xb7d4c35e, 0x5bea61af, 0xfdf530d6, 0x7efa986b, 0xef7d4c34, 0x77bea61a, 0x3bdf530d, + 0xcdefa987, 0xb6f7d4c2, 0x5b7bea61, 0xfdbdf531, 0xaedefa99, 0x876f7d4d, 0x93b7bea7, 0x99dbdf52, + 0x4cedefa9, 0xf676f7d5, 0xab3b7beb, 0x859dbdf4, 0x42cedefa, 0x21676f7d, 0xc0b3b7bf, 0xb059dbde, + 0x582cedef, 0xfc1676f6, 0x7e0b3b7b, 0xef059dbc, 0x7782cede, 0x3bc1676f, 0xcde0b3b6, 0x66f059db, + 0xe3782cec, 0x71bc1676, 0x38de0b3b, 0xcc6f059c, 0x663782ce, 0x331bc167, 0xc98de0b2, 0x64c6f059, + 0xe263782d, 0xa131bc17, 0x8098de0a, 0x404c6f05, 0xf0263783, 0xa8131bc0, 0x54098de0, 0x2a04c6f0, + 0x15026378, 0x0a8131bc, 0x054098de, 0x02a04c6f, 0xd1502636, 0x68a8131b, 0xe454098c, 0x722a04c6, + 0x39150263, 0xcc8a8130, 0x66454098, 0x3322a04c, 0x19915026, 0x0cc8a813, 0xd6645408, 0x6b322a04, + 0x35991502, 0x1acc8a81, 0xdd664541, 0xbeb322a1, 0x8f599151, 0x97acc8a9, 0x9bd66455, 0x9deb322b, + 0x9ef59914, 0x4f7acc8a, 0x27bd6645, 0xc3deb323, 0xb1ef5990, 0x58f7acc8, 0x2c7bd664, 0x163deb32, + 0x0b1ef599, 0xd58f7acd, 0xbac7bd67, 0x8d63deb2, 0x46b1ef59, 0xf358f7ad, 0xa9ac7bd7, 0x84d63dea, + 0x426b1ef5, 0xf1358f7b, 0xa89ac7bc, 0x544d63de, 0x2a26b1ef, 0xc51358f6, 0x6289ac7b, 0xe144d63c, + 0x70a26b1e, 0x3851358f, 0xcc289ac6, 0x66144d63, 0xe30a26b0, 0x71851358, 0x38c289ac, 0x1c6144d6, + 0x0e30a26b, 0xd7185134, 0x6b8c289a, 0x35c6144d, 0xcae30a27, 0xb5718512, 0x5ab8c289, 0xfd5c6145, + 0xaeae30a3, 0x87571850, 0x43ab8c28, 0x21d5c614, 0x10eae30a, 0x08757185, 0xd43ab8c3, 0xba1d5c60, + 0x5d0eae30, 0x2e875718, 0x1743ab8c, 0x0ba1d5c6, 0x05d0eae3, 0xd2e87570, 0x69743ab8, 0x34ba1d5c, + 0x1a5d0eae, 0x0d2e8757, 0xd69743aa, 0x6b4ba1d5, 0xe5a5d0eb, 0xa2d2e874, 0x5169743a, 0x28b4ba1d, + 0xc45a5d0f, 0xb22d2e86, 0x59169743, 0xfc8b4ba0, 0x7e45a5d0, 0x3f22d2e8, 0x1f916974, 0x0fc8b4ba, + 0x07e45a5d, 0xd3f22d2f, 0xb9f91696, 0x5cfc8b4b, 0xfe7e45a4, 0x7f3f22d2, 0x3f9f9169, 0xcfcfc8b5, + 0xb7e7e45b, 0x8bf3f22c, 0x45f9f916, 0x22fcfc8b, 0xc17e7e44, 0x60bf3f22, 0x305f9f91, 0xc82fcfc9, + 0xb417e7e5, 0x8a0bf3f3, 0x9505f9f8, 0x4a82fcfc, 0x25417e7e, 0x12a0bf3f, 0xd9505f9e, 0x6ca82fcf, + 0xe65417e6, 0x732a0bf3, 0xe99505f8, 0x74ca82fc, 0x3a65417e, 0x1d32a0bf, 0xde99505e, 0x6f4ca82f, + 0xe7a65416, 0x73d32a0b, 0xe9e99504, 0x74f4ca82, 0x3a7a6541, 0xcd3d32a1, 0xb69e9951, 0x8b4f4ca9, + 0x95a7a655, 0x9ad3d32b, 0x9d69e994, 0x4eb4f4ca, 0x275a7a65, 0xc3ad3d33, 0xb1d69e98, 0x58eb4f4c, + 0x2c75a7a6, 0x163ad3d3, 0xdb1d69e8, 0x6d8eb4f4, 0x36c75a7a, 0x1b63ad3d, 0xddb1d69f, 0xbed8eb4e, + 0x5f6c75a7, 0xffb63ad2, 0x7fdb1d69, 0xefed8eb5, 0xa7f6c75b, 0x83fb63ac, 0x41fdb1d6, 0x20fed8eb, + 0xc07f6c74, 0x603fb63a, 0x301fdb1d, 0xc80fed8f, 0xb407f6c6, 0x5a03fb63, 0xfd01fdb0, 0x7e80fed8, + 0x3f407f6c, 0x1fa03fb6, 0x0fd01fdb, 0xd7e80fec, 0x6bf407f6, 0x35fa03fb, 0xcafd01fc, 0x657e80fe, + 0x32bf407f, 0xc95fa03e, 0x64afd01f, 0xe257e80e, 0x712bf407, 0xe895fa02, 0x744afd01, 0xea257e81, + 0xa512bf41, 0x82895fa1, 0x9144afd1, 0x98a257e9, 0x9c512bf5, 0x9e2895fb, 0x9f144afc, 0x4f8a257e, + 0x27c512bf, 0xc3e2895e, 0x61f144af, 0xe0f8a256, 0x707c512b, 0xe83e2894, 0x741f144a, 0x3a0f8a25, + 0xcd07c513, 0xb683e288, 0x5b41f144, 0x2da0f8a2, 0x16d07c51, 0xdb683e29, 0xbdb41f15, 0x8eda0f8b, + 0x976d07c4, 0x4bb683e2, 0x25db41f1, 0xc2eda0f9, 0xb176d07d, 0x88bb683f, 0x945db41e, 0x4a2eda0f, + 0xf5176d06, 0x7a8bb683, 0xed45db40, 0x76a2eda0, 0x3b5176d0, 0x1da8bb68, 0x0ed45db4, 0x076a2eda, + 0x03b5176d, 0xd1da8bb7, 0xb8ed45da, 0x5c76a2ed, 0xfe3b5177, 0xaf1da8ba, 0x578ed45d, 0xfbc76a2f, + 0xade3b516, 0x56f1da8b, 0xfb78ed44, 0x7dbc76a2, 0x3ede3b51, 0xcf6f1da9, 0xb7b78ed5, 0x8bdbc76b, + 0x95ede3b4, 0x4af6f1da, 0x257b78ed, 0xc2bdbc77, 0xb15ede3a, 0x58af6f1d, 0xfc57b78f, 0xae2bdbc6, + 0x5715ede3, 0xfb8af6f0, 0x7dc57b78, 0x3ee2bdbc, 0x1f715ede, 0x0fb8af6f, 0xd7dc57b6, 0x6bee2bdb, +}; + +void lane256_compress(const u8 m[64], u32 h[8], const u32 ctrh, const u32 ctrl) +{ + u32 t0, t1, t2, t3, t4, t5, t6, t7; /* temp */ + u32 s00, s01, s02, s03, s04, s05, s06, s07; /* lane 0 */ + u32 s10, s11, s12, s13, s14, s15, s16, s17; /* lane 1 */ + u32 s20, s21, s22, s23, s24, s25, s26, s27; /* lane 2 */ + u32 s30, s31, s32, s33, s34, s35, s36, s37; /* lane 3 */ + u32 s40, s41, s42, s43, s44, s45, s46, s47; /* lane 4 */ + u32 s50, s51, s52, s53, s54, s55, s56, s57; /* lane 5 */ + u32 s60, s61, s62, s63, s64, s65, s66, s67; /* lane 6 */ + u32 s70, s71, s72, s73, s74, s75, s76, s77; /* lane 7 */ + + /* Message expansion */ + s30 = h[0]; + s31 = h[1]; + s32 = h[2]; + s33 = h[3]; + s34 = h[4]; + s35 = h[5]; + s36 = h[6]; + s37 = h[7]; + s40 = U8TO32_BIG(m + 0); + s41 = U8TO32_BIG(m + 4); + s42 = U8TO32_BIG(m + 8); + s43 = U8TO32_BIG(m + 12); + s44 = U8TO32_BIG(m + 16); + s45 = U8TO32_BIG(m + 20); + s46 = U8TO32_BIG(m + 24); + s47 = U8TO32_BIG(m + 28); + s50 = U8TO32_BIG(m + 32); + s51 = U8TO32_BIG(m + 36); + s52 = U8TO32_BIG(m + 40); + s53 = U8TO32_BIG(m + 44); + s54 = U8TO32_BIG(m + 48); + s55 = U8TO32_BIG(m + 52); + s56 = U8TO32_BIG(m + 56); + s57 = U8TO32_BIG(m + 60); + s00 = s30 ^ s40 ^ s44 ^ s50 ^ s54; + s01 = s31 ^ s41 ^ s45 ^ s51 ^ s55; + s02 = s32 ^ s42 ^ s46 ^ s52 ^ s56; + s03 = s33 ^ s43 ^ s47 ^ s53 ^ s57; + s04 = s34 ^ s40 ^ s50; + s05 = s35 ^ s41 ^ s51; + s06 = s36 ^ s42 ^ s52; + s07 = s37 ^ s43 ^ s53; + s10 = s00 ^ s34 ^ s44; + s11 = s01 ^ s35 ^ s45; + s12 = s02 ^ s36 ^ s46; + s13 = s03 ^ s37 ^ s47; + s14 = s30 ^ s44 ^ s50; + s15 = s31 ^ s45 ^ s51; + s16 = s32 ^ s46 ^ s52; + s17 = s33 ^ s47 ^ s53; + s20 = s00 ^ s34 ^ s54; + s21 = s01 ^ s35 ^ s55; + s22 = s02 ^ s36 ^ s56; + s23 = s03 ^ s37 ^ s57; + s24 = s30 ^ s40 ^ s54; + s25 = s31 ^ s41 ^ s55; + s26 = s32 ^ s42 ^ s56; + s27 = s33 ^ s43 ^ s57; + + /* Lane 0 */ + t0 = T0[B3(s00)] ^ T1[B2(s01)] ^ T2[B1(s02)] ^ T3[B0(s03)] ^ C[ 0]; + t1 = T0[B3(s01)] ^ T1[B2(s02)] ^ T2[B1(s03)] ^ T3[B0(s00)] ^ C[ 1]; + t4 = T0[B3(s02)] ^ T1[B2(s03)] ^ T2[B1(s00)] ^ T3[B0(s01)] ^ C[ 2]; + t5 = T0[B3(s03)] ^ T1[B2(s00)] ^ T2[B1(s01)] ^ T3[B0(s02)] ^ C[ 3] ^ ctrh; + t2 = T0[B3(s04)] ^ T1[B2(s05)] ^ T2[B1(s06)] ^ T3[B0(s07)] ^ C[ 4]; + t3 = T0[B3(s05)] ^ T1[B2(s06)] ^ T2[B1(s07)] ^ T3[B0(s04)] ^ C[ 5]; + t6 = T0[B3(s06)] ^ T1[B2(s07)] ^ T2[B1(s04)] ^ T3[B0(s05)] ^ C[ 6]; + t7 = T0[B3(s07)] ^ T1[B2(s04)] ^ T2[B1(s05)] ^ T3[B0(s06)] ^ C[ 7]; + + s00 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 8]; + s01 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 9]; + s04 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[10]; + s05 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[11] ^ ctrl; + s02 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[12]; + s03 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[13]; + s06 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[14]; + s07 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[15]; + + t0 = T0[B3(s00)] ^ T1[B2(s01)] ^ T2[B1(s02)] ^ T3[B0(s03)] ^ C[16]; + t1 = T0[B3(s01)] ^ T1[B2(s02)] ^ T2[B1(s03)] ^ T3[B0(s00)] ^ C[17]; + t4 = T0[B3(s02)] ^ T1[B2(s03)] ^ T2[B1(s00)] ^ T3[B0(s01)] ^ C[18]; + t5 = T0[B3(s03)] ^ T1[B2(s00)] ^ T2[B1(s01)] ^ T3[B0(s02)] ^ C[19] ^ ctrh; + t2 = T0[B3(s04)] ^ T1[B2(s05)] ^ T2[B1(s06)] ^ T3[B0(s07)] ^ C[20]; + t3 = T0[B3(s05)] ^ T1[B2(s06)] ^ T2[B1(s07)] ^ T3[B0(s04)] ^ C[21]; + t6 = T0[B3(s06)] ^ T1[B2(s07)] ^ T2[B1(s04)] ^ T3[B0(s05)] ^ C[22]; + t7 = T0[B3(s07)] ^ T1[B2(s04)] ^ T2[B1(s05)] ^ T3[B0(s06)] ^ C[23]; + + s00 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[24]; + s01 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[25]; + s04 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[26]; + s05 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[27] ^ ctrl; + s02 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[28]; + s03 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[29]; + s06 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[30]; + s07 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[31]; + + t0 = T0[B3(s00)] ^ T1[B2(s01)] ^ T2[B1(s02)] ^ T3[B0(s03)] ^ C[32]; + t1 = T0[B3(s01)] ^ T1[B2(s02)] ^ T2[B1(s03)] ^ T3[B0(s00)] ^ C[33]; + t4 = T0[B3(s02)] ^ T1[B2(s03)] ^ T2[B1(s00)] ^ T3[B0(s01)] ^ C[34]; + t5 = T0[B3(s03)] ^ T1[B2(s00)] ^ T2[B1(s01)] ^ T3[B0(s02)] ^ C[35] ^ ctrh; + t2 = T0[B3(s04)] ^ T1[B2(s05)] ^ T2[B1(s06)] ^ T3[B0(s07)] ^ C[36]; + t3 = T0[B3(s05)] ^ T1[B2(s06)] ^ T2[B1(s07)] ^ T3[B0(s04)] ^ C[37]; + t6 = T0[B3(s06)] ^ T1[B2(s07)] ^ T2[B1(s04)] ^ T3[B0(s05)] ^ C[38]; + t7 = T0[B3(s07)] ^ T1[B2(s04)] ^ T2[B1(s05)] ^ T3[B0(s06)] ^ C[39]; + + s60 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )]; + s61 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )]; + s64 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )]; + s65 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )]; + s62 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )]; + s63 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )]; + s66 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )]; + s67 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )]; + + /* Lane 1 */ + t0 = T0[B3(s10)] ^ T1[B2(s11)] ^ T2[B1(s12)] ^ T3[B0(s13)] ^ C[ 0+40]; + t1 = T0[B3(s11)] ^ T1[B2(s12)] ^ T2[B1(s13)] ^ T3[B0(s10)] ^ C[ 1+40]; + t4 = T0[B3(s12)] ^ T1[B2(s13)] ^ T2[B1(s10)] ^ T3[B0(s11)] ^ C[ 2+40]; + t5 = T0[B3(s13)] ^ T1[B2(s10)] ^ T2[B1(s11)] ^ T3[B0(s12)] ^ C[ 3+40] ^ ctrl; + t2 = T0[B3(s14)] ^ T1[B2(s15)] ^ T2[B1(s16)] ^ T3[B0(s17)] ^ C[ 4+40]; + t3 = T0[B3(s15)] ^ T1[B2(s16)] ^ T2[B1(s17)] ^ T3[B0(s14)] ^ C[ 5+40]; + t6 = T0[B3(s16)] ^ T1[B2(s17)] ^ T2[B1(s14)] ^ T3[B0(s15)] ^ C[ 6+40]; + t7 = T0[B3(s17)] ^ T1[B2(s14)] ^ T2[B1(s15)] ^ T3[B0(s16)] ^ C[ 7+40]; + + s10 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 8+40]; + s11 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 9+40]; + s14 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[10+40]; + s15 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[11+40] ^ ctrh; + s12 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[12+40]; + s13 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[13+40]; + s16 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[14+40]; + s17 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[15+40]; + + t0 = T0[B3(s10)] ^ T1[B2(s11)] ^ T2[B1(s12)] ^ T3[B0(s13)] ^ C[16+40]; + t1 = T0[B3(s11)] ^ T1[B2(s12)] ^ T2[B1(s13)] ^ T3[B0(s10)] ^ C[17+40]; + t4 = T0[B3(s12)] ^ T1[B2(s13)] ^ T2[B1(s10)] ^ T3[B0(s11)] ^ C[18+40]; + t5 = T0[B3(s13)] ^ T1[B2(s10)] ^ T2[B1(s11)] ^ T3[B0(s12)] ^ C[19+40] ^ ctrl; + t2 = T0[B3(s14)] ^ T1[B2(s15)] ^ T2[B1(s16)] ^ T3[B0(s17)] ^ C[20+40]; + t3 = T0[B3(s15)] ^ T1[B2(s16)] ^ T2[B1(s17)] ^ T3[B0(s14)] ^ C[21+40]; + t6 = T0[B3(s16)] ^ T1[B2(s17)] ^ T2[B1(s14)] ^ T3[B0(s15)] ^ C[22+40]; + t7 = T0[B3(s17)] ^ T1[B2(s14)] ^ T2[B1(s15)] ^ T3[B0(s16)] ^ C[23+40]; + + s10 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[24+40]; + s11 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[25+40]; + s14 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[26+40]; + s15 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[27+40] ^ ctrh; + s12 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[28+40]; + s13 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[29+40]; + s16 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[30+40]; + s17 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[31+40]; + + t0 = T0[B3(s10)] ^ T1[B2(s11)] ^ T2[B1(s12)] ^ T3[B0(s13)] ^ C[32+40]; + t1 = T0[B3(s11)] ^ T1[B2(s12)] ^ T2[B1(s13)] ^ T3[B0(s10)] ^ C[33+40]; + t4 = T0[B3(s12)] ^ T1[B2(s13)] ^ T2[B1(s10)] ^ T3[B0(s11)] ^ C[34+40]; + t5 = T0[B3(s13)] ^ T1[B2(s10)] ^ T2[B1(s11)] ^ T3[B0(s12)] ^ C[35+40] ^ ctrl; + t2 = T0[B3(s14)] ^ T1[B2(s15)] ^ T2[B1(s16)] ^ T3[B0(s17)] ^ C[36+40]; + t3 = T0[B3(s15)] ^ T1[B2(s16)] ^ T2[B1(s17)] ^ T3[B0(s14)] ^ C[37+40]; + t6 = T0[B3(s16)] ^ T1[B2(s17)] ^ T2[B1(s14)] ^ T3[B0(s15)] ^ C[38+40]; + t7 = T0[B3(s17)] ^ T1[B2(s14)] ^ T2[B1(s15)] ^ T3[B0(s16)] ^ C[39+40]; + + s60 ^= T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )]; + s61 ^= T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )]; + s64 ^= T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )]; + s65 ^= T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )]; + s62 ^= T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )]; + s63 ^= T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )]; + s66 ^= T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )]; + s67 ^= T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )]; + + /* Lane 2 */ + t0 = T0[B3(s20)] ^ T1[B2(s21)] ^ T2[B1(s22)] ^ T3[B0(s23)] ^ C[ 0+80]; + t1 = T0[B3(s21)] ^ T1[B2(s22)] ^ T2[B1(s23)] ^ T3[B0(s20)] ^ C[ 1+80]; + t4 = T0[B3(s22)] ^ T1[B2(s23)] ^ T2[B1(s20)] ^ T3[B0(s21)] ^ C[ 2+80]; + t5 = T0[B3(s23)] ^ T1[B2(s20)] ^ T2[B1(s21)] ^ T3[B0(s22)] ^ C[ 3+80] ^ ctrh; + t2 = T0[B3(s24)] ^ T1[B2(s25)] ^ T2[B1(s26)] ^ T3[B0(s27)] ^ C[ 4+80]; + t3 = T0[B3(s25)] ^ T1[B2(s26)] ^ T2[B1(s27)] ^ T3[B0(s24)] ^ C[ 5+80]; + t6 = T0[B3(s26)] ^ T1[B2(s27)] ^ T2[B1(s24)] ^ T3[B0(s25)] ^ C[ 6+80]; + t7 = T0[B3(s27)] ^ T1[B2(s24)] ^ T2[B1(s25)] ^ T3[B0(s26)] ^ C[ 7+80]; + + s20 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 8+80]; + s21 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 9+80]; + s24 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[10+80]; + s25 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[11+80] ^ ctrl; + s22 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[12+80]; + s23 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[13+80]; + s26 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[14+80]; + s27 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[15+80]; + + t0 = T0[B3(s20)] ^ T1[B2(s21)] ^ T2[B1(s22)] ^ T3[B0(s23)] ^ C[16+80]; + t1 = T0[B3(s21)] ^ T1[B2(s22)] ^ T2[B1(s23)] ^ T3[B0(s20)] ^ C[17+80]; + t4 = T0[B3(s22)] ^ T1[B2(s23)] ^ T2[B1(s20)] ^ T3[B0(s21)] ^ C[18+80]; + t5 = T0[B3(s23)] ^ T1[B2(s20)] ^ T2[B1(s21)] ^ T3[B0(s22)] ^ C[19+80] ^ ctrh; + t2 = T0[B3(s24)] ^ T1[B2(s25)] ^ T2[B1(s26)] ^ T3[B0(s27)] ^ C[20+80]; + t3 = T0[B3(s25)] ^ T1[B2(s26)] ^ T2[B1(s27)] ^ T3[B0(s24)] ^ C[21+80]; + t6 = T0[B3(s26)] ^ T1[B2(s27)] ^ T2[B1(s24)] ^ T3[B0(s25)] ^ C[22+80]; + t7 = T0[B3(s27)] ^ T1[B2(s24)] ^ T2[B1(s25)] ^ T3[B0(s26)] ^ C[23+80]; + + s20 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[24+80]; + s21 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[25+80]; + s24 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[26+80]; + s25 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[27+80] ^ ctrl; + s22 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[28+80]; + s23 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[29+80]; + s26 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[30+80]; + s27 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[31+80]; + + t0 = T0[B3(s20)] ^ T1[B2(s21)] ^ T2[B1(s22)] ^ T3[B0(s23)] ^ C[32+80]; + t1 = T0[B3(s21)] ^ T1[B2(s22)] ^ T2[B1(s23)] ^ T3[B0(s20)] ^ C[33+80]; + t4 = T0[B3(s22)] ^ T1[B2(s23)] ^ T2[B1(s20)] ^ T3[B0(s21)] ^ C[34+80]; + t5 = T0[B3(s23)] ^ T1[B2(s20)] ^ T2[B1(s21)] ^ T3[B0(s22)] ^ C[35+80] ^ ctrh; + t2 = T0[B3(s24)] ^ T1[B2(s25)] ^ T2[B1(s26)] ^ T3[B0(s27)] ^ C[36+80]; + t3 = T0[B3(s25)] ^ T1[B2(s26)] ^ T2[B1(s27)] ^ T3[B0(s24)] ^ C[37+80]; + t6 = T0[B3(s26)] ^ T1[B2(s27)] ^ T2[B1(s24)] ^ T3[B0(s25)] ^ C[38+80]; + t7 = T0[B3(s27)] ^ T1[B2(s24)] ^ T2[B1(s25)] ^ T3[B0(s26)] ^ C[39+80]; + + s60 ^= T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )]; + s61 ^= T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )]; + s64 ^= T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )]; + s65 ^= T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )]; + s62 ^= T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )]; + s63 ^= T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )]; + s66 ^= T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )]; + s67 ^= T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )]; + + /* Lane 3 */ + t0 = T0[B3(s30)] ^ T1[B2(s31)] ^ T2[B1(s32)] ^ T3[B0(s33)] ^ C[ 0+120]; + t1 = T0[B3(s31)] ^ T1[B2(s32)] ^ T2[B1(s33)] ^ T3[B0(s30)] ^ C[ 1+120]; + t4 = T0[B3(s32)] ^ T1[B2(s33)] ^ T2[B1(s30)] ^ T3[B0(s31)] ^ C[ 2+120]; + t5 = T0[B3(s33)] ^ T1[B2(s30)] ^ T2[B1(s31)] ^ T3[B0(s32)] ^ C[ 3+120] ^ ctrl; + t2 = T0[B3(s34)] ^ T1[B2(s35)] ^ T2[B1(s36)] ^ T3[B0(s37)] ^ C[ 4+120]; + t3 = T0[B3(s35)] ^ T1[B2(s36)] ^ T2[B1(s37)] ^ T3[B0(s34)] ^ C[ 5+120]; + t6 = T0[B3(s36)] ^ T1[B2(s37)] ^ T2[B1(s34)] ^ T3[B0(s35)] ^ C[ 6+120]; + t7 = T0[B3(s37)] ^ T1[B2(s34)] ^ T2[B1(s35)] ^ T3[B0(s36)] ^ C[ 7+120]; + + s30 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 8+120]; + s31 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 9+120]; + s34 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[10+120]; + s35 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[11+120] ^ ctrh; + s32 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[12+120]; + s33 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[13+120]; + s36 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[14+120]; + s37 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[15+120]; + + t0 = T0[B3(s30)] ^ T1[B2(s31)] ^ T2[B1(s32)] ^ T3[B0(s33)] ^ C[16+120]; + t1 = T0[B3(s31)] ^ T1[B2(s32)] ^ T2[B1(s33)] ^ T3[B0(s30)] ^ C[17+120]; + t4 = T0[B3(s32)] ^ T1[B2(s33)] ^ T2[B1(s30)] ^ T3[B0(s31)] ^ C[18+120]; + t5 = T0[B3(s33)] ^ T1[B2(s30)] ^ T2[B1(s31)] ^ T3[B0(s32)] ^ C[19+120] ^ ctrl; + t2 = T0[B3(s34)] ^ T1[B2(s35)] ^ T2[B1(s36)] ^ T3[B0(s37)] ^ C[20+120]; + t3 = T0[B3(s35)] ^ T1[B2(s36)] ^ T2[B1(s37)] ^ T3[B0(s34)] ^ C[21+120]; + t6 = T0[B3(s36)] ^ T1[B2(s37)] ^ T2[B1(s34)] ^ T3[B0(s35)] ^ C[22+120]; + t7 = T0[B3(s37)] ^ T1[B2(s34)] ^ T2[B1(s35)] ^ T3[B0(s36)] ^ C[23+120]; + + s30 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[24+120]; + s31 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[25+120]; + s34 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[26+120]; + s35 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[27+120] ^ ctrh; + s32 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[28+120]; + s33 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[29+120]; + s36 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[30+120]; + s37 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[31+120]; + + t0 = T0[B3(s30)] ^ T1[B2(s31)] ^ T2[B1(s32)] ^ T3[B0(s33)] ^ C[32+120]; + t1 = T0[B3(s31)] ^ T1[B2(s32)] ^ T2[B1(s33)] ^ T3[B0(s30)] ^ C[33+120]; + t4 = T0[B3(s32)] ^ T1[B2(s33)] ^ T2[B1(s30)] ^ T3[B0(s31)] ^ C[34+120]; + t5 = T0[B3(s33)] ^ T1[B2(s30)] ^ T2[B1(s31)] ^ T3[B0(s32)] ^ C[35+120] ^ ctrl; + t2 = T0[B3(s34)] ^ T1[B2(s35)] ^ T2[B1(s36)] ^ T3[B0(s37)] ^ C[36+120]; + t3 = T0[B3(s35)] ^ T1[B2(s36)] ^ T2[B1(s37)] ^ T3[B0(s34)] ^ C[37+120]; + t6 = T0[B3(s36)] ^ T1[B2(s37)] ^ T2[B1(s34)] ^ T3[B0(s35)] ^ C[38+120]; + t7 = T0[B3(s37)] ^ T1[B2(s34)] ^ T2[B1(s35)] ^ T3[B0(s36)] ^ C[39+120]; + + s70 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )]; + s71 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )]; + s74 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )]; + s75 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )]; + s72 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )]; + s73 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )]; + s76 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )]; + s77 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )]; + + /* Lane 4 */ + t0 = T0[B3(s40)] ^ T1[B2(s41)] ^ T2[B1(s42)] ^ T3[B0(s43)] ^ C[ 0+160]; + t1 = T0[B3(s41)] ^ T1[B2(s42)] ^ T2[B1(s43)] ^ T3[B0(s40)] ^ C[ 1+160]; + t4 = T0[B3(s42)] ^ T1[B2(s43)] ^ T2[B1(s40)] ^ T3[B0(s41)] ^ C[ 2+160]; + t5 = T0[B3(s43)] ^ T1[B2(s40)] ^ T2[B1(s41)] ^ T3[B0(s42)] ^ C[ 3+160] ^ ctrh; + t2 = T0[B3(s44)] ^ T1[B2(s45)] ^ T2[B1(s46)] ^ T3[B0(s47)] ^ C[ 4+160]; + t3 = T0[B3(s45)] ^ T1[B2(s46)] ^ T2[B1(s47)] ^ T3[B0(s44)] ^ C[ 5+160]; + t6 = T0[B3(s46)] ^ T1[B2(s47)] ^ T2[B1(s44)] ^ T3[B0(s45)] ^ C[ 6+160]; + t7 = T0[B3(s47)] ^ T1[B2(s44)] ^ T2[B1(s45)] ^ T3[B0(s46)] ^ C[ 7+160]; + + s40 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 8+160]; + s41 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 9+160]; + s44 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[10+160]; + s45 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[11+160] ^ ctrl; + s42 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[12+160]; + s43 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[13+160]; + s46 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[14+160]; + s47 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[15+160]; + + t0 = T0[B3(s40)] ^ T1[B2(s41)] ^ T2[B1(s42)] ^ T3[B0(s43)] ^ C[16+160]; + t1 = T0[B3(s41)] ^ T1[B2(s42)] ^ T2[B1(s43)] ^ T3[B0(s40)] ^ C[17+160]; + t4 = T0[B3(s42)] ^ T1[B2(s43)] ^ T2[B1(s40)] ^ T3[B0(s41)] ^ C[18+160]; + t5 = T0[B3(s43)] ^ T1[B2(s40)] ^ T2[B1(s41)] ^ T3[B0(s42)] ^ C[19+160] ^ ctrh; + t2 = T0[B3(s44)] ^ T1[B2(s45)] ^ T2[B1(s46)] ^ T3[B0(s47)] ^ C[20+160]; + t3 = T0[B3(s45)] ^ T1[B2(s46)] ^ T2[B1(s47)] ^ T3[B0(s44)] ^ C[21+160]; + t6 = T0[B3(s46)] ^ T1[B2(s47)] ^ T2[B1(s44)] ^ T3[B0(s45)] ^ C[22+160]; + t7 = T0[B3(s47)] ^ T1[B2(s44)] ^ T2[B1(s45)] ^ T3[B0(s46)] ^ C[23+160]; + + s40 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[24+160]; + s41 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[25+160]; + s44 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[26+160]; + s45 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[27+160] ^ ctrl; + s42 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[28+160]; + s43 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[29+160]; + s46 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[30+160]; + s47 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[31+160]; + + t0 = T0[B3(s40)] ^ T1[B2(s41)] ^ T2[B1(s42)] ^ T3[B0(s43)] ^ C[32+160]; + t1 = T0[B3(s41)] ^ T1[B2(s42)] ^ T2[B1(s43)] ^ T3[B0(s40)] ^ C[33+160]; + t4 = T0[B3(s42)] ^ T1[B2(s43)] ^ T2[B1(s40)] ^ T3[B0(s41)] ^ C[34+160]; + t5 = T0[B3(s43)] ^ T1[B2(s40)] ^ T2[B1(s41)] ^ T3[B0(s42)] ^ C[35+160] ^ ctrh; + t2 = T0[B3(s44)] ^ T1[B2(s45)] ^ T2[B1(s46)] ^ T3[B0(s47)] ^ C[36+160]; + t3 = T0[B3(s45)] ^ T1[B2(s46)] ^ T2[B1(s47)] ^ T3[B0(s44)] ^ C[37+160]; + t6 = T0[B3(s46)] ^ T1[B2(s47)] ^ T2[B1(s44)] ^ T3[B0(s45)] ^ C[38+160]; + t7 = T0[B3(s47)] ^ T1[B2(s44)] ^ T2[B1(s45)] ^ T3[B0(s46)] ^ C[39+160]; + + s70 ^= T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )]; + s71 ^= T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )]; + s74 ^= T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )]; + s75 ^= T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )]; + s72 ^= T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )]; + s73 ^= T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )]; + s76 ^= T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )]; + s77 ^= T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )]; + + /* Lane 5 */ + t0 = T0[B3(s50)] ^ T1[B2(s51)] ^ T2[B1(s52)] ^ T3[B0(s53)] ^ C[ 0+200]; + t1 = T0[B3(s51)] ^ T1[B2(s52)] ^ T2[B1(s53)] ^ T3[B0(s50)] ^ C[ 1+200]; + t4 = T0[B3(s52)] ^ T1[B2(s53)] ^ T2[B1(s50)] ^ T3[B0(s51)] ^ C[ 2+200]; + t5 = T0[B3(s53)] ^ T1[B2(s50)] ^ T2[B1(s51)] ^ T3[B0(s52)] ^ C[ 3+200] ^ ctrl; + t2 = T0[B3(s54)] ^ T1[B2(s55)] ^ T2[B1(s56)] ^ T3[B0(s57)] ^ C[ 4+200]; + t3 = T0[B3(s55)] ^ T1[B2(s56)] ^ T2[B1(s57)] ^ T3[B0(s54)] ^ C[ 5+200]; + t6 = T0[B3(s56)] ^ T1[B2(s57)] ^ T2[B1(s54)] ^ T3[B0(s55)] ^ C[ 6+200]; + t7 = T0[B3(s57)] ^ T1[B2(s54)] ^ T2[B1(s55)] ^ T3[B0(s56)] ^ C[ 7+200]; + + s50 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 8+200]; + s51 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 9+200]; + s54 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[10+200]; + s55 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[11+200] ^ ctrh; + s52 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[12+200]; + s53 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[13+200]; + s56 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[14+200]; + s57 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[15+200]; + + t0 = T0[B3(s50)] ^ T1[B2(s51)] ^ T2[B1(s52)] ^ T3[B0(s53)] ^ C[16+200]; + t1 = T0[B3(s51)] ^ T1[B2(s52)] ^ T2[B1(s53)] ^ T3[B0(s50)] ^ C[17+200]; + t4 = T0[B3(s52)] ^ T1[B2(s53)] ^ T2[B1(s50)] ^ T3[B0(s51)] ^ C[18+200]; + t5 = T0[B3(s53)] ^ T1[B2(s50)] ^ T2[B1(s51)] ^ T3[B0(s52)] ^ C[19+200] ^ ctrl; + t2 = T0[B3(s54)] ^ T1[B2(s55)] ^ T2[B1(s56)] ^ T3[B0(s57)] ^ C[20+200]; + t3 = T0[B3(s55)] ^ T1[B2(s56)] ^ T2[B1(s57)] ^ T3[B0(s54)] ^ C[21+200]; + t6 = T0[B3(s56)] ^ T1[B2(s57)] ^ T2[B1(s54)] ^ T3[B0(s55)] ^ C[22+200]; + t7 = T0[B3(s57)] ^ T1[B2(s54)] ^ T2[B1(s55)] ^ T3[B0(s56)] ^ C[23+200]; + + s50 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[24+200]; + s51 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[25+200]; + s54 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[26+200]; + s55 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[27+200] ^ ctrh; + s52 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[28+200]; + s53 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[29+200]; + s56 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[30+200]; + s57 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[31+200]; + + t0 = T0[B3(s50)] ^ T1[B2(s51)] ^ T2[B1(s52)] ^ T3[B0(s53)] ^ C[32+200]; + t1 = T0[B3(s51)] ^ T1[B2(s52)] ^ T2[B1(s53)] ^ T3[B0(s50)] ^ C[33+200]; + t4 = T0[B3(s52)] ^ T1[B2(s53)] ^ T2[B1(s50)] ^ T3[B0(s51)] ^ C[34+200]; + t5 = T0[B3(s53)] ^ T1[B2(s50)] ^ T2[B1(s51)] ^ T3[B0(s52)] ^ C[35+200] ^ ctrl; + t2 = T0[B3(s54)] ^ T1[B2(s55)] ^ T2[B1(s56)] ^ T3[B0(s57)] ^ C[36+200]; + t3 = T0[B3(s55)] ^ T1[B2(s56)] ^ T2[B1(s57)] ^ T3[B0(s54)] ^ C[37+200]; + t6 = T0[B3(s56)] ^ T1[B2(s57)] ^ T2[B1(s54)] ^ T3[B0(s55)] ^ C[38+200]; + t7 = T0[B3(s57)] ^ T1[B2(s54)] ^ T2[B1(s55)] ^ T3[B0(s56)] ^ C[39+200]; + + s70 ^= T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )]; + s71 ^= T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )]; + s74 ^= T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )]; + s75 ^= T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )]; + s72 ^= T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )]; + s73 ^= T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )]; + s76 ^= T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )]; + s77 ^= T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )]; + + /* Lane 6 */ + t0 = T0[B3(s60)] ^ T1[B2(s61)] ^ T2[B1(s62)] ^ T3[B0(s63)] ^ C[ 0+240]; + t1 = T0[B3(s61)] ^ T1[B2(s62)] ^ T2[B1(s63)] ^ T3[B0(s60)] ^ C[ 1+240]; + t4 = T0[B3(s62)] ^ T1[B2(s63)] ^ T2[B1(s60)] ^ T3[B0(s61)] ^ C[ 2+240]; + t5 = T0[B3(s63)] ^ T1[B2(s60)] ^ T2[B1(s61)] ^ T3[B0(s62)] ^ C[ 3+240] ^ ctrh; + t2 = T0[B3(s64)] ^ T1[B2(s65)] ^ T2[B1(s66)] ^ T3[B0(s67)] ^ C[ 4+240]; + t3 = T0[B3(s65)] ^ T1[B2(s66)] ^ T2[B1(s67)] ^ T3[B0(s64)] ^ C[ 5+240]; + t6 = T0[B3(s66)] ^ T1[B2(s67)] ^ T2[B1(s64)] ^ T3[B0(s65)] ^ C[ 6+240]; + t7 = T0[B3(s67)] ^ T1[B2(s64)] ^ T2[B1(s65)] ^ T3[B0(s66)] ^ C[ 7+240]; + + s60 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 8+240]; + s61 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 9+240]; + s64 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[10+240]; + s65 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[11+240] ^ ctrl; + s62 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[12+240]; + s63 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[13+240]; + s66 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[14+240]; + s67 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[15+240]; + + h[0] = T0[B3(s60)] ^ T1[B2(s61)] ^ T2[B1(s62)] ^ T3[B0(s63)]; + h[1] = T0[B3(s61)] ^ T1[B2(s62)] ^ T2[B1(s63)] ^ T3[B0(s60)]; + h[4] = T0[B3(s62)] ^ T1[B2(s63)] ^ T2[B1(s60)] ^ T3[B0(s61)]; + h[5] = T0[B3(s63)] ^ T1[B2(s60)] ^ T2[B1(s61)] ^ T3[B0(s62)]; + h[2] = T0[B3(s64)] ^ T1[B2(s65)] ^ T2[B1(s66)] ^ T3[B0(s67)]; + h[3] = T0[B3(s65)] ^ T1[B2(s66)] ^ T2[B1(s67)] ^ T3[B0(s64)]; + h[6] = T0[B3(s66)] ^ T1[B2(s67)] ^ T2[B1(s64)] ^ T3[B0(s65)]; + h[7] = T0[B3(s67)] ^ T1[B2(s64)] ^ T2[B1(s65)] ^ T3[B0(s66)]; + + /* Lane 7 */ + t0 = T0[B3(s70)] ^ T1[B2(s71)] ^ T2[B1(s72)] ^ T3[B0(s73)] ^ C[ 0+256]; + t1 = T0[B3(s71)] ^ T1[B2(s72)] ^ T2[B1(s73)] ^ T3[B0(s70)] ^ C[ 1+256]; + t4 = T0[B3(s72)] ^ T1[B2(s73)] ^ T2[B1(s70)] ^ T3[B0(s71)] ^ C[ 2+256]; + t5 = T0[B3(s73)] ^ T1[B2(s70)] ^ T2[B1(s71)] ^ T3[B0(s72)] ^ C[ 3+256] ^ ctrh; + t2 = T0[B3(s74)] ^ T1[B2(s75)] ^ T2[B1(s76)] ^ T3[B0(s77)] ^ C[ 4+256]; + t3 = T0[B3(s75)] ^ T1[B2(s76)] ^ T2[B1(s77)] ^ T3[B0(s74)] ^ C[ 5+256]; + t6 = T0[B3(s76)] ^ T1[B2(s77)] ^ T2[B1(s74)] ^ T3[B0(s75)] ^ C[ 6+256]; + t7 = T0[B3(s77)] ^ T1[B2(s74)] ^ T2[B1(s75)] ^ T3[B0(s76)] ^ C[ 7+256]; + + s70 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 8+256]; + s71 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 9+256]; + s74 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[10+256]; + s75 = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[11+256] ^ ctrl; + s72 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[12+256]; + s73 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[13+256]; + s76 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[14+256]; + s77 = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[15+256]; + + h[0] ^= T0[B3(s70)] ^ T1[B2(s71)] ^ T2[B1(s72)] ^ T3[B0(s73)]; + h[1] ^= T0[B3(s71)] ^ T1[B2(s72)] ^ T2[B1(s73)] ^ T3[B0(s70)]; + h[4] ^= T0[B3(s72)] ^ T1[B2(s73)] ^ T2[B1(s70)] ^ T3[B0(s71)]; + h[5] ^= T0[B3(s73)] ^ T1[B2(s70)] ^ T2[B1(s71)] ^ T3[B0(s72)]; + h[2] ^= T0[B3(s74)] ^ T1[B2(s75)] ^ T2[B1(s76)] ^ T3[B0(s77)]; + h[3] ^= T0[B3(s75)] ^ T1[B2(s76)] ^ T2[B1(s77)] ^ T3[B0(s74)]; + h[6] ^= T0[B3(s76)] ^ T1[B2(s77)] ^ T2[B1(s74)] ^ T3[B0(s75)]; + h[7] ^= T0[B3(s77)] ^ T1[B2(s74)] ^ T2[B1(s75)] ^ T3[B0(s76)]; +} + +void lane512_compress(const u8 m[128], u32 h[16], const u32 ctrh, const u32 ctrl) +{ + u32 t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, ta, tb, tc, td, te, tf; /* temp */ + u32 s00, s01, s02, s03, s04, s05, s06, s07, s08, s09, s0a, s0b, s0c, s0d, s0e, s0f; /* lane 0 */ + u32 s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s1a, s1b, s1c, s1d, s1e, s1f; /* lane 1 */ + u32 s20, s21, s22, s23, s24, s25, s26, s27, s28, s29, s2a, s2b, s2c, s2d, s2e, s2f; /* lane 2 */ + u32 s30, s31, s32, s33, s34, s35, s36, s37, s38, s39, s3a, s3b, s3c, s3d, s3e, s3f; /* lane 3 */ + u32 s40, s41, s42, s43, s44, s45, s46, s47, s48, s49, s4a, s4b, s4c, s4d, s4e, s4f; /* lane 4 */ + u32 s50, s51, s52, s53, s54, s55, s56, s57, s58, s59, s5a, s5b, s5c, s5d, s5e, s5f; /* lane 5 */ + u32 s60, s61, s62, s63, s64, s65, s66, s67, s68, s69, s6a, s6b, s6c, s6d, s6e, s6f; /* lane 6 */ + u32 s70, s71, s72, s73, s74, s75, s76, s77, s78, s79, s7a, s7b, s7c, s7d, s7e, s7f; /* lane 7 */ + + /* Message expansion */ + s30 = h[0]; + s31 = h[1]; + s32 = h[2]; + s33 = h[3]; + s34 = h[4]; + s35 = h[5]; + s36 = h[6]; + s37 = h[7]; + s38 = h[8]; + s39 = h[9]; + s3a = h[10]; + s3b = h[11]; + s3c = h[12]; + s3d = h[13]; + s3e = h[14]; + s3f = h[15]; + s40 = U8TO32_BIG(m + 0); + s41 = U8TO32_BIG(m + 4); + s42 = U8TO32_BIG(m + 8); + s43 = U8TO32_BIG(m + 12); + s44 = U8TO32_BIG(m + 16); + s45 = U8TO32_BIG(m + 20); + s46 = U8TO32_BIG(m + 24); + s47 = U8TO32_BIG(m + 28); + s48 = U8TO32_BIG(m + 32); + s49 = U8TO32_BIG(m + 36); + s4a = U8TO32_BIG(m + 40); + s4b = U8TO32_BIG(m + 44); + s4c = U8TO32_BIG(m + 48); + s4d = U8TO32_BIG(m + 52); + s4e = U8TO32_BIG(m + 56); + s4f = U8TO32_BIG(m + 60); + s50 = U8TO32_BIG(m + 64); + s51 = U8TO32_BIG(m + 68); + s52 = U8TO32_BIG(m + 72); + s53 = U8TO32_BIG(m + 76); + s54 = U8TO32_BIG(m + 80); + s55 = U8TO32_BIG(m + 84); + s56 = U8TO32_BIG(m + 88); + s57 = U8TO32_BIG(m + 92); + s58 = U8TO32_BIG(m + 96); + s59 = U8TO32_BIG(m + 100); + s5a = U8TO32_BIG(m + 104); + s5b = U8TO32_BIG(m + 108); + s5c = U8TO32_BIG(m + 112); + s5d = U8TO32_BIG(m + 116); + s5e = U8TO32_BIG(m + 120); + s5f = U8TO32_BIG(m + 124); + s00 = s30 ^ s40 ^ s48 ^ s50 ^ s58; + s01 = s31 ^ s41 ^ s49 ^ s51 ^ s59; + s02 = s32 ^ s42 ^ s4a ^ s52 ^ s5a; + s03 = s33 ^ s43 ^ s4b ^ s53 ^ s5b; + s04 = s34 ^ s44 ^ s4c ^ s54 ^ s5c; + s05 = s35 ^ s45 ^ s4d ^ s55 ^ s5d; + s06 = s36 ^ s46 ^ s4e ^ s56 ^ s5e; + s07 = s37 ^ s47 ^ s4f ^ s57 ^ s5f; + s08 = s38 ^ s40 ^ s50; + s09 = s39 ^ s41 ^ s51; + s0a = s3a ^ s42 ^ s52; + s0b = s3b ^ s43 ^ s53; + s0c = s3c ^ s44 ^ s54; + s0d = s3d ^ s45 ^ s55; + s0e = s3e ^ s46 ^ s56; + s0f = s3f ^ s47 ^ s57; + s10 = s00 ^ s38 ^ s48; + s11 = s01 ^ s39 ^ s49; + s12 = s02 ^ s3a ^ s4a; + s13 = s03 ^ s3b ^ s4b; + s14 = s04 ^ s3c ^ s4c; + s15 = s05 ^ s3d ^ s4d; + s16 = s06 ^ s3e ^ s4e; + s17 = s07 ^ s3f ^ s4f; + s18 = s30 ^ s48 ^ s50; + s19 = s31 ^ s49 ^ s51; + s1a = s32 ^ s4a ^ s52; + s1b = s33 ^ s4b ^ s53; + s1c = s34 ^ s4c ^ s54; + s1d = s35 ^ s4d ^ s55; + s1e = s36 ^ s4e ^ s56; + s1f = s37 ^ s4f ^ s57; + s20 = s00 ^ s38 ^ s58; + s21 = s01 ^ s39 ^ s59; + s22 = s02 ^ s3a ^ s5a; + s23 = s03 ^ s3b ^ s5b; + s24 = s04 ^ s3c ^ s5c; + s25 = s05 ^ s3d ^ s5d; + s26 = s06 ^ s3e ^ s5e; + s27 = s07 ^ s3f ^ s5f; + s28 = s30 ^ s40 ^ s58; + s29 = s31 ^ s41 ^ s59; + s2a = s32 ^ s42 ^ s5a; + s2b = s33 ^ s43 ^ s5b; + s2c = s34 ^ s44 ^ s5c; + s2d = s35 ^ s45 ^ s5d; + s2e = s36 ^ s46 ^ s5e; + s2f = s37 ^ s47 ^ s5f; + + /* Lane 0 */ + t0 = T0[B3(s00)] ^ T1[B2(s01)] ^ T2[B1(s02)] ^ T3[B0(s03)] ^ C[ 0]; + t4 = T0[B3(s01)] ^ T1[B2(s02)] ^ T2[B1(s03)] ^ T3[B0(s00)] ^ C[ 1]; + t8 = T0[B3(s02)] ^ T1[B2(s03)] ^ T2[B1(s00)] ^ T3[B0(s01)] ^ C[ 2]; + tc = T0[B3(s03)] ^ T1[B2(s00)] ^ T2[B1(s01)] ^ T3[B0(s02)] ^ C[ 3] ^ ctrh; + t1 = T0[B3(s04)] ^ T1[B2(s05)] ^ T2[B1(s06)] ^ T3[B0(s07)] ^ C[ 4]; + t5 = T0[B3(s05)] ^ T1[B2(s06)] ^ T2[B1(s07)] ^ T3[B0(s04)] ^ C[ 5]; + t9 = T0[B3(s06)] ^ T1[B2(s07)] ^ T2[B1(s04)] ^ T3[B0(s05)] ^ C[ 6]; + td = T0[B3(s07)] ^ T1[B2(s04)] ^ T2[B1(s05)] ^ T3[B0(s06)] ^ C[ 7]; + t2 = T0[B3(s08)] ^ T1[B2(s09)] ^ T2[B1(s0a)] ^ T3[B0(s0b)] ^ C[ 8]; + t6 = T0[B3(s09)] ^ T1[B2(s0a)] ^ T2[B1(s0b)] ^ T3[B0(s08)] ^ C[ 9]; + ta = T0[B3(s0a)] ^ T1[B2(s0b)] ^ T2[B1(s08)] ^ T3[B0(s09)] ^ C[ 10]; + te = T0[B3(s0b)] ^ T1[B2(s08)] ^ T2[B1(s09)] ^ T3[B0(s0a)] ^ C[ 11]; + t3 = T0[B3(s0c)] ^ T1[B2(s0d)] ^ T2[B1(s0e)] ^ T3[B0(s0f)] ^ C[ 12]; + t7 = T0[B3(s0d)] ^ T1[B2(s0e)] ^ T2[B1(s0f)] ^ T3[B0(s0c)] ^ C[ 13]; + tb = T0[B3(s0e)] ^ T1[B2(s0f)] ^ T2[B1(s0c)] ^ T3[B0(s0d)] ^ C[ 14]; + tf = T0[B3(s0f)] ^ T1[B2(s0c)] ^ T2[B1(s0d)] ^ T3[B0(s0e)] ^ C[ 15]; + + s00 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 16]; + s04 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 17]; + s08 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 18]; + s0c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 19] ^ ctrl; + s01 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 20]; + s05 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 21]; + s09 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 22]; + s0d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 23]; + s02 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 24]; + s06 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 25]; + s0a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 26]; + s0e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 27]; + s03 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 28]; + s07 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 29]; + s0b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 30]; + s0f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 31]; + + t0 = T0[B3(s00)] ^ T1[B2(s01)] ^ T2[B1(s02)] ^ T3[B0(s03)] ^ C[ 32]; + t4 = T0[B3(s01)] ^ T1[B2(s02)] ^ T2[B1(s03)] ^ T3[B0(s00)] ^ C[ 33]; + t8 = T0[B3(s02)] ^ T1[B2(s03)] ^ T2[B1(s00)] ^ T3[B0(s01)] ^ C[ 34]; + tc = T0[B3(s03)] ^ T1[B2(s00)] ^ T2[B1(s01)] ^ T3[B0(s02)] ^ C[ 35] ^ ctrh; + t1 = T0[B3(s04)] ^ T1[B2(s05)] ^ T2[B1(s06)] ^ T3[B0(s07)] ^ C[ 36]; + t5 = T0[B3(s05)] ^ T1[B2(s06)] ^ T2[B1(s07)] ^ T3[B0(s04)] ^ C[ 37]; + t9 = T0[B3(s06)] ^ T1[B2(s07)] ^ T2[B1(s04)] ^ T3[B0(s05)] ^ C[ 38]; + td = T0[B3(s07)] ^ T1[B2(s04)] ^ T2[B1(s05)] ^ T3[B0(s06)] ^ C[ 39]; + t2 = T0[B3(s08)] ^ T1[B2(s09)] ^ T2[B1(s0a)] ^ T3[B0(s0b)] ^ C[ 40]; + t6 = T0[B3(s09)] ^ T1[B2(s0a)] ^ T2[B1(s0b)] ^ T3[B0(s08)] ^ C[ 41]; + ta = T0[B3(s0a)] ^ T1[B2(s0b)] ^ T2[B1(s08)] ^ T3[B0(s09)] ^ C[ 42]; + te = T0[B3(s0b)] ^ T1[B2(s08)] ^ T2[B1(s09)] ^ T3[B0(s0a)] ^ C[ 43]; + t3 = T0[B3(s0c)] ^ T1[B2(s0d)] ^ T2[B1(s0e)] ^ T3[B0(s0f)] ^ C[ 44]; + t7 = T0[B3(s0d)] ^ T1[B2(s0e)] ^ T2[B1(s0f)] ^ T3[B0(s0c)] ^ C[ 45]; + tb = T0[B3(s0e)] ^ T1[B2(s0f)] ^ T2[B1(s0c)] ^ T3[B0(s0d)] ^ C[ 46]; + tf = T0[B3(s0f)] ^ T1[B2(s0c)] ^ T2[B1(s0d)] ^ T3[B0(s0e)] ^ C[ 47]; + + s00 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 48]; + s04 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 49]; + s08 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 50]; + s0c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 51] ^ ctrl; + s01 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 52]; + s05 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 53]; + s09 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 54]; + s0d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 55]; + s02 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 56]; + s06 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 57]; + s0a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 58]; + s0e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 59]; + s03 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 60]; + s07 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 61]; + s0b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 62]; + s0f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 63]; + + t0 = T0[B3(s00)] ^ T1[B2(s01)] ^ T2[B1(s02)] ^ T3[B0(s03)] ^ C[ 64]; + t4 = T0[B3(s01)] ^ T1[B2(s02)] ^ T2[B1(s03)] ^ T3[B0(s00)] ^ C[ 65]; + t8 = T0[B3(s02)] ^ T1[B2(s03)] ^ T2[B1(s00)] ^ T3[B0(s01)] ^ C[ 66]; + tc = T0[B3(s03)] ^ T1[B2(s00)] ^ T2[B1(s01)] ^ T3[B0(s02)] ^ C[ 67] ^ ctrh; + t1 = T0[B3(s04)] ^ T1[B2(s05)] ^ T2[B1(s06)] ^ T3[B0(s07)] ^ C[ 68]; + t5 = T0[B3(s05)] ^ T1[B2(s06)] ^ T2[B1(s07)] ^ T3[B0(s04)] ^ C[ 69]; + t9 = T0[B3(s06)] ^ T1[B2(s07)] ^ T2[B1(s04)] ^ T3[B0(s05)] ^ C[ 70]; + td = T0[B3(s07)] ^ T1[B2(s04)] ^ T2[B1(s05)] ^ T3[B0(s06)] ^ C[ 71]; + t2 = T0[B3(s08)] ^ T1[B2(s09)] ^ T2[B1(s0a)] ^ T3[B0(s0b)] ^ C[ 72]; + t6 = T0[B3(s09)] ^ T1[B2(s0a)] ^ T2[B1(s0b)] ^ T3[B0(s08)] ^ C[ 73]; + ta = T0[B3(s0a)] ^ T1[B2(s0b)] ^ T2[B1(s08)] ^ T3[B0(s09)] ^ C[ 74]; + te = T0[B3(s0b)] ^ T1[B2(s08)] ^ T2[B1(s09)] ^ T3[B0(s0a)] ^ C[ 75]; + t3 = T0[B3(s0c)] ^ T1[B2(s0d)] ^ T2[B1(s0e)] ^ T3[B0(s0f)] ^ C[ 76]; + t7 = T0[B3(s0d)] ^ T1[B2(s0e)] ^ T2[B1(s0f)] ^ T3[B0(s0c)] ^ C[ 77]; + tb = T0[B3(s0e)] ^ T1[B2(s0f)] ^ T2[B1(s0c)] ^ T3[B0(s0d)] ^ C[ 78]; + tf = T0[B3(s0f)] ^ T1[B2(s0c)] ^ T2[B1(s0d)] ^ T3[B0(s0e)] ^ C[ 79]; + + s00 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 80]; + s04 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 81]; + s08 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 82]; + s0c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 83] ^ ctrl; + s01 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 84]; + s05 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 85]; + s09 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 86]; + s0d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 87]; + s02 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 88]; + s06 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 89]; + s0a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 90]; + s0e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 91]; + s03 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 92]; + s07 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 93]; + s0b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 94]; + s0f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 95]; + + t0 = T0[B3(s00)] ^ T1[B2(s01)] ^ T2[B1(s02)] ^ T3[B0(s03)] ^ C[ 96]; + t4 = T0[B3(s01)] ^ T1[B2(s02)] ^ T2[B1(s03)] ^ T3[B0(s00)] ^ C[ 97]; + t8 = T0[B3(s02)] ^ T1[B2(s03)] ^ T2[B1(s00)] ^ T3[B0(s01)] ^ C[ 98]; + tc = T0[B3(s03)] ^ T1[B2(s00)] ^ T2[B1(s01)] ^ T3[B0(s02)] ^ C[ 99] ^ ctrh; + t1 = T0[B3(s04)] ^ T1[B2(s05)] ^ T2[B1(s06)] ^ T3[B0(s07)] ^ C[100]; + t5 = T0[B3(s05)] ^ T1[B2(s06)] ^ T2[B1(s07)] ^ T3[B0(s04)] ^ C[101]; + t9 = T0[B3(s06)] ^ T1[B2(s07)] ^ T2[B1(s04)] ^ T3[B0(s05)] ^ C[102]; + td = T0[B3(s07)] ^ T1[B2(s04)] ^ T2[B1(s05)] ^ T3[B0(s06)] ^ C[103]; + t2 = T0[B3(s08)] ^ T1[B2(s09)] ^ T2[B1(s0a)] ^ T3[B0(s0b)] ^ C[104]; + t6 = T0[B3(s09)] ^ T1[B2(s0a)] ^ T2[B1(s0b)] ^ T3[B0(s08)] ^ C[105]; + ta = T0[B3(s0a)] ^ T1[B2(s0b)] ^ T2[B1(s08)] ^ T3[B0(s09)] ^ C[106]; + te = T0[B3(s0b)] ^ T1[B2(s08)] ^ T2[B1(s09)] ^ T3[B0(s0a)] ^ C[107]; + t3 = T0[B3(s0c)] ^ T1[B2(s0d)] ^ T2[B1(s0e)] ^ T3[B0(s0f)] ^ C[108]; + t7 = T0[B3(s0d)] ^ T1[B2(s0e)] ^ T2[B1(s0f)] ^ T3[B0(s0c)] ^ C[109]; + tb = T0[B3(s0e)] ^ T1[B2(s0f)] ^ T2[B1(s0c)] ^ T3[B0(s0d)] ^ C[110]; + tf = T0[B3(s0f)] ^ T1[B2(s0c)] ^ T2[B1(s0d)] ^ T3[B0(s0e)] ^ C[111]; + + s60 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )]; + s64 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )]; + s68 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )]; + s6c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )]; + s61 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )]; + s65 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )]; + s69 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )]; + s6d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )]; + s62 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )]; + s66 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )]; + s6a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )]; + s6e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )]; + s63 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )]; + s67 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )]; + s6b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )]; + s6f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )]; + + /* Lane 1 */ + t0 = T0[B3(s10)] ^ T1[B2(s11)] ^ T2[B1(s12)] ^ T3[B0(s13)] ^ C[ 0+112]; + t4 = T0[B3(s11)] ^ T1[B2(s12)] ^ T2[B1(s13)] ^ T3[B0(s10)] ^ C[ 1+112]; + t8 = T0[B3(s12)] ^ T1[B2(s13)] ^ T2[B1(s10)] ^ T3[B0(s11)] ^ C[ 2+112]; + tc = T0[B3(s13)] ^ T1[B2(s10)] ^ T2[B1(s11)] ^ T3[B0(s12)] ^ C[ 3+112] ^ ctrl; + t1 = T0[B3(s14)] ^ T1[B2(s15)] ^ T2[B1(s16)] ^ T3[B0(s17)] ^ C[ 4+112]; + t5 = T0[B3(s15)] ^ T1[B2(s16)] ^ T2[B1(s17)] ^ T3[B0(s14)] ^ C[ 5+112]; + t9 = T0[B3(s16)] ^ T1[B2(s17)] ^ T2[B1(s14)] ^ T3[B0(s15)] ^ C[ 6+112]; + td = T0[B3(s17)] ^ T1[B2(s14)] ^ T2[B1(s15)] ^ T3[B0(s16)] ^ C[ 7+112]; + t2 = T0[B3(s18)] ^ T1[B2(s19)] ^ T2[B1(s1a)] ^ T3[B0(s1b)] ^ C[ 8+112]; + t6 = T0[B3(s19)] ^ T1[B2(s1a)] ^ T2[B1(s1b)] ^ T3[B0(s18)] ^ C[ 9+112]; + ta = T0[B3(s1a)] ^ T1[B2(s1b)] ^ T2[B1(s18)] ^ T3[B0(s19)] ^ C[ 10+112]; + te = T0[B3(s1b)] ^ T1[B2(s18)] ^ T2[B1(s19)] ^ T3[B0(s1a)] ^ C[ 11+112]; + t3 = T0[B3(s1c)] ^ T1[B2(s1d)] ^ T2[B1(s1e)] ^ T3[B0(s1f)] ^ C[ 12+112]; + t7 = T0[B3(s1d)] ^ T1[B2(s1e)] ^ T2[B1(s1f)] ^ T3[B0(s1c)] ^ C[ 13+112]; + tb = T0[B3(s1e)] ^ T1[B2(s1f)] ^ T2[B1(s1c)] ^ T3[B0(s1d)] ^ C[ 14+112]; + tf = T0[B3(s1f)] ^ T1[B2(s1c)] ^ T2[B1(s1d)] ^ T3[B0(s1e)] ^ C[ 15+112]; + + s10 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 16+112]; + s14 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 17+112]; + s18 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 18+112]; + s1c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 19+112] ^ ctrh; + s11 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 20+112]; + s15 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 21+112]; + s19 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 22+112]; + s1d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 23+112]; + s12 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 24+112]; + s16 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 25+112]; + s1a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 26+112]; + s1e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 27+112]; + s13 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 28+112]; + s17 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 29+112]; + s1b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 30+112]; + s1f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 31+112]; + + t0 = T0[B3(s10)] ^ T1[B2(s11)] ^ T2[B1(s12)] ^ T3[B0(s13)] ^ C[ 32+112]; + t4 = T0[B3(s11)] ^ T1[B2(s12)] ^ T2[B1(s13)] ^ T3[B0(s10)] ^ C[ 33+112]; + t8 = T0[B3(s12)] ^ T1[B2(s13)] ^ T2[B1(s10)] ^ T3[B0(s11)] ^ C[ 34+112]; + tc = T0[B3(s13)] ^ T1[B2(s10)] ^ T2[B1(s11)] ^ T3[B0(s12)] ^ C[ 35+112] ^ ctrl; + t1 = T0[B3(s14)] ^ T1[B2(s15)] ^ T2[B1(s16)] ^ T3[B0(s17)] ^ C[ 36+112]; + t5 = T0[B3(s15)] ^ T1[B2(s16)] ^ T2[B1(s17)] ^ T3[B0(s14)] ^ C[ 37+112]; + t9 = T0[B3(s16)] ^ T1[B2(s17)] ^ T2[B1(s14)] ^ T3[B0(s15)] ^ C[ 38+112]; + td = T0[B3(s17)] ^ T1[B2(s14)] ^ T2[B1(s15)] ^ T3[B0(s16)] ^ C[ 39+112]; + t2 = T0[B3(s18)] ^ T1[B2(s19)] ^ T2[B1(s1a)] ^ T3[B0(s1b)] ^ C[ 40+112]; + t6 = T0[B3(s19)] ^ T1[B2(s1a)] ^ T2[B1(s1b)] ^ T3[B0(s18)] ^ C[ 41+112]; + ta = T0[B3(s1a)] ^ T1[B2(s1b)] ^ T2[B1(s18)] ^ T3[B0(s19)] ^ C[ 42+112]; + te = T0[B3(s1b)] ^ T1[B2(s18)] ^ T2[B1(s19)] ^ T3[B0(s1a)] ^ C[ 43+112]; + t3 = T0[B3(s1c)] ^ T1[B2(s1d)] ^ T2[B1(s1e)] ^ T3[B0(s1f)] ^ C[ 44+112]; + t7 = T0[B3(s1d)] ^ T1[B2(s1e)] ^ T2[B1(s1f)] ^ T3[B0(s1c)] ^ C[ 45+112]; + tb = T0[B3(s1e)] ^ T1[B2(s1f)] ^ T2[B1(s1c)] ^ T3[B0(s1d)] ^ C[ 46+112]; + tf = T0[B3(s1f)] ^ T1[B2(s1c)] ^ T2[B1(s1d)] ^ T3[B0(s1e)] ^ C[ 47+112]; + + s10 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 48+112]; + s14 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 49+112]; + s18 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 50+112]; + s1c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 51+112] ^ ctrh; + s11 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 52+112]; + s15 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 53+112]; + s19 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 54+112]; + s1d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 55+112]; + s12 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 56+112]; + s16 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 57+112]; + s1a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 58+112]; + s1e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 59+112]; + s13 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 60+112]; + s17 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 61+112]; + s1b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 62+112]; + s1f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 63+112]; + + t0 = T0[B3(s10)] ^ T1[B2(s11)] ^ T2[B1(s12)] ^ T3[B0(s13)] ^ C[ 64+112]; + t4 = T0[B3(s11)] ^ T1[B2(s12)] ^ T2[B1(s13)] ^ T3[B0(s10)] ^ C[ 65+112]; + t8 = T0[B3(s12)] ^ T1[B2(s13)] ^ T2[B1(s10)] ^ T3[B0(s11)] ^ C[ 66+112]; + tc = T0[B3(s13)] ^ T1[B2(s10)] ^ T2[B1(s11)] ^ T3[B0(s12)] ^ C[ 67+112] ^ ctrl; + t1 = T0[B3(s14)] ^ T1[B2(s15)] ^ T2[B1(s16)] ^ T3[B0(s17)] ^ C[ 68+112]; + t5 = T0[B3(s15)] ^ T1[B2(s16)] ^ T2[B1(s17)] ^ T3[B0(s14)] ^ C[ 69+112]; + t9 = T0[B3(s16)] ^ T1[B2(s17)] ^ T2[B1(s14)] ^ T3[B0(s15)] ^ C[ 70+112]; + td = T0[B3(s17)] ^ T1[B2(s14)] ^ T2[B1(s15)] ^ T3[B0(s16)] ^ C[ 71+112]; + t2 = T0[B3(s18)] ^ T1[B2(s19)] ^ T2[B1(s1a)] ^ T3[B0(s1b)] ^ C[ 72+112]; + t6 = T0[B3(s19)] ^ T1[B2(s1a)] ^ T2[B1(s1b)] ^ T3[B0(s18)] ^ C[ 73+112]; + ta = T0[B3(s1a)] ^ T1[B2(s1b)] ^ T2[B1(s18)] ^ T3[B0(s19)] ^ C[ 74+112]; + te = T0[B3(s1b)] ^ T1[B2(s18)] ^ T2[B1(s19)] ^ T3[B0(s1a)] ^ C[ 75+112]; + t3 = T0[B3(s1c)] ^ T1[B2(s1d)] ^ T2[B1(s1e)] ^ T3[B0(s1f)] ^ C[ 76+112]; + t7 = T0[B3(s1d)] ^ T1[B2(s1e)] ^ T2[B1(s1f)] ^ T3[B0(s1c)] ^ C[ 77+112]; + tb = T0[B3(s1e)] ^ T1[B2(s1f)] ^ T2[B1(s1c)] ^ T3[B0(s1d)] ^ C[ 78+112]; + tf = T0[B3(s1f)] ^ T1[B2(s1c)] ^ T2[B1(s1d)] ^ T3[B0(s1e)] ^ C[ 79+112]; + + s10 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 80+112]; + s14 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 81+112]; + s18 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 82+112]; + s1c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 83+112] ^ ctrh; + s11 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 84+112]; + s15 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 85+112]; + s19 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 86+112]; + s1d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 87+112]; + s12 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 88+112]; + s16 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 89+112]; + s1a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 90+112]; + s1e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 91+112]; + s13 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 92+112]; + s17 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 93+112]; + s1b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 94+112]; + s1f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 95+112]; + + t0 = T0[B3(s10)] ^ T1[B2(s11)] ^ T2[B1(s12)] ^ T3[B0(s13)] ^ C[ 96+112]; + t4 = T0[B3(s11)] ^ T1[B2(s12)] ^ T2[B1(s13)] ^ T3[B0(s10)] ^ C[ 97+112]; + t8 = T0[B3(s12)] ^ T1[B2(s13)] ^ T2[B1(s10)] ^ T3[B0(s11)] ^ C[ 98+112]; + tc = T0[B3(s13)] ^ T1[B2(s10)] ^ T2[B1(s11)] ^ T3[B0(s12)] ^ C[ 99+112] ^ ctrl; + t1 = T0[B3(s14)] ^ T1[B2(s15)] ^ T2[B1(s16)] ^ T3[B0(s17)] ^ C[100+112]; + t5 = T0[B3(s15)] ^ T1[B2(s16)] ^ T2[B1(s17)] ^ T3[B0(s14)] ^ C[101+112]; + t9 = T0[B3(s16)] ^ T1[B2(s17)] ^ T2[B1(s14)] ^ T3[B0(s15)] ^ C[102+112]; + td = T0[B3(s17)] ^ T1[B2(s14)] ^ T2[B1(s15)] ^ T3[B0(s16)] ^ C[103+112]; + t2 = T0[B3(s18)] ^ T1[B2(s19)] ^ T2[B1(s1a)] ^ T3[B0(s1b)] ^ C[104+112]; + t6 = T0[B3(s19)] ^ T1[B2(s1a)] ^ T2[B1(s1b)] ^ T3[B0(s18)] ^ C[105+112]; + ta = T0[B3(s1a)] ^ T1[B2(s1b)] ^ T2[B1(s18)] ^ T3[B0(s19)] ^ C[106+112]; + te = T0[B3(s1b)] ^ T1[B2(s18)] ^ T2[B1(s19)] ^ T3[B0(s1a)] ^ C[107+112]; + t3 = T0[B3(s1c)] ^ T1[B2(s1d)] ^ T2[B1(s1e)] ^ T3[B0(s1f)] ^ C[108+112]; + t7 = T0[B3(s1d)] ^ T1[B2(s1e)] ^ T2[B1(s1f)] ^ T3[B0(s1c)] ^ C[109+112]; + tb = T0[B3(s1e)] ^ T1[B2(s1f)] ^ T2[B1(s1c)] ^ T3[B0(s1d)] ^ C[110+112]; + tf = T0[B3(s1f)] ^ T1[B2(s1c)] ^ T2[B1(s1d)] ^ T3[B0(s1e)] ^ C[111+112]; + + s60 ^= T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )]; + s64 ^= T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )]; + s68 ^= T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )]; + s6c ^= T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )]; + s61 ^= T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )]; + s65 ^= T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )]; + s69 ^= T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )]; + s6d ^= T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )]; + s62 ^= T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )]; + s66 ^= T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )]; + s6a ^= T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )]; + s6e ^= T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )]; + s63 ^= T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )]; + s67 ^= T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )]; + s6b ^= T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )]; + s6f ^= T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )]; + + /* Lane 2 */ + t0 = T0[B3(s20)] ^ T1[B2(s21)] ^ T2[B1(s22)] ^ T3[B0(s23)] ^ C[ 0+224]; + t4 = T0[B3(s21)] ^ T1[B2(s22)] ^ T2[B1(s23)] ^ T3[B0(s20)] ^ C[ 1+224]; + t8 = T0[B3(s22)] ^ T1[B2(s23)] ^ T2[B1(s20)] ^ T3[B0(s21)] ^ C[ 2+224]; + tc = T0[B3(s23)] ^ T1[B2(s20)] ^ T2[B1(s21)] ^ T3[B0(s22)] ^ C[ 3+224] ^ ctrh; + t1 = T0[B3(s24)] ^ T1[B2(s25)] ^ T2[B1(s26)] ^ T3[B0(s27)] ^ C[ 4+224]; + t5 = T0[B3(s25)] ^ T1[B2(s26)] ^ T2[B1(s27)] ^ T3[B0(s24)] ^ C[ 5+224]; + t9 = T0[B3(s26)] ^ T1[B2(s27)] ^ T2[B1(s24)] ^ T3[B0(s25)] ^ C[ 6+224]; + td = T0[B3(s27)] ^ T1[B2(s24)] ^ T2[B1(s25)] ^ T3[B0(s26)] ^ C[ 7+224]; + t2 = T0[B3(s28)] ^ T1[B2(s29)] ^ T2[B1(s2a)] ^ T3[B0(s2b)] ^ C[ 8+224]; + t6 = T0[B3(s29)] ^ T1[B2(s2a)] ^ T2[B1(s2b)] ^ T3[B0(s28)] ^ C[ 9+224]; + ta = T0[B3(s2a)] ^ T1[B2(s2b)] ^ T2[B1(s28)] ^ T3[B0(s29)] ^ C[ 10+224]; + te = T0[B3(s2b)] ^ T1[B2(s28)] ^ T2[B1(s29)] ^ T3[B0(s2a)] ^ C[ 11+224]; + t3 = T0[B3(s2c)] ^ T1[B2(s2d)] ^ T2[B1(s2e)] ^ T3[B0(s2f)] ^ C[ 12+224]; + t7 = T0[B3(s2d)] ^ T1[B2(s2e)] ^ T2[B1(s2f)] ^ T3[B0(s2c)] ^ C[ 13+224]; + tb = T0[B3(s2e)] ^ T1[B2(s2f)] ^ T2[B1(s2c)] ^ T3[B0(s2d)] ^ C[ 14+224]; + tf = T0[B3(s2f)] ^ T1[B2(s2c)] ^ T2[B1(s2d)] ^ T3[B0(s2e)] ^ C[ 15+224]; + + s20 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 16+224]; + s24 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 17+224]; + s28 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 18+224]; + s2c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 19+224] ^ ctrl; + s21 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 20+224]; + s25 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 21+224]; + s29 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 22+224]; + s2d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 23+224]; + s22 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 24+224]; + s26 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 25+224]; + s2a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 26+224]; + s2e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 27+224]; + s23 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 28+224]; + s27 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 29+224]; + s2b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 30+224]; + s2f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 31+224]; + + t0 = T0[B3(s20)] ^ T1[B2(s21)] ^ T2[B1(s22)] ^ T3[B0(s23)] ^ C[ 32+224]; + t4 = T0[B3(s21)] ^ T1[B2(s22)] ^ T2[B1(s23)] ^ T3[B0(s20)] ^ C[ 33+224]; + t8 = T0[B3(s22)] ^ T1[B2(s23)] ^ T2[B1(s20)] ^ T3[B0(s21)] ^ C[ 34+224]; + tc = T0[B3(s23)] ^ T1[B2(s20)] ^ T2[B1(s21)] ^ T3[B0(s22)] ^ C[ 35+224] ^ ctrh; + t1 = T0[B3(s24)] ^ T1[B2(s25)] ^ T2[B1(s26)] ^ T3[B0(s27)] ^ C[ 36+224]; + t5 = T0[B3(s25)] ^ T1[B2(s26)] ^ T2[B1(s27)] ^ T3[B0(s24)] ^ C[ 37+224]; + t9 = T0[B3(s26)] ^ T1[B2(s27)] ^ T2[B1(s24)] ^ T3[B0(s25)] ^ C[ 38+224]; + td = T0[B3(s27)] ^ T1[B2(s24)] ^ T2[B1(s25)] ^ T3[B0(s26)] ^ C[ 39+224]; + t2 = T0[B3(s28)] ^ T1[B2(s29)] ^ T2[B1(s2a)] ^ T3[B0(s2b)] ^ C[ 40+224]; + t6 = T0[B3(s29)] ^ T1[B2(s2a)] ^ T2[B1(s2b)] ^ T3[B0(s28)] ^ C[ 41+224]; + ta = T0[B3(s2a)] ^ T1[B2(s2b)] ^ T2[B1(s28)] ^ T3[B0(s29)] ^ C[ 42+224]; + te = T0[B3(s2b)] ^ T1[B2(s28)] ^ T2[B1(s29)] ^ T3[B0(s2a)] ^ C[ 43+224]; + t3 = T0[B3(s2c)] ^ T1[B2(s2d)] ^ T2[B1(s2e)] ^ T3[B0(s2f)] ^ C[ 44+224]; + t7 = T0[B3(s2d)] ^ T1[B2(s2e)] ^ T2[B1(s2f)] ^ T3[B0(s2c)] ^ C[ 45+224]; + tb = T0[B3(s2e)] ^ T1[B2(s2f)] ^ T2[B1(s2c)] ^ T3[B0(s2d)] ^ C[ 46+224]; + tf = T0[B3(s2f)] ^ T1[B2(s2c)] ^ T2[B1(s2d)] ^ T3[B0(s2e)] ^ C[ 47+224]; + + s20 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 48+224]; + s24 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 49+224]; + s28 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 50+224]; + s2c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 51+224] ^ ctrl; + s21 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 52+224]; + s25 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 53+224]; + s29 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 54+224]; + s2d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 55+224]; + s22 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 56+224]; + s26 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 57+224]; + s2a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 58+224]; + s2e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 59+224]; + s23 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 60+224]; + s27 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 61+224]; + s2b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 62+224]; + s2f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 63+224]; + + t0 = T0[B3(s20)] ^ T1[B2(s21)] ^ T2[B1(s22)] ^ T3[B0(s23)] ^ C[ 64+224]; + t4 = T0[B3(s21)] ^ T1[B2(s22)] ^ T2[B1(s23)] ^ T3[B0(s20)] ^ C[ 65+224]; + t8 = T0[B3(s22)] ^ T1[B2(s23)] ^ T2[B1(s20)] ^ T3[B0(s21)] ^ C[ 66+224]; + tc = T0[B3(s23)] ^ T1[B2(s20)] ^ T2[B1(s21)] ^ T3[B0(s22)] ^ C[ 67+224] ^ ctrh; + t1 = T0[B3(s24)] ^ T1[B2(s25)] ^ T2[B1(s26)] ^ T3[B0(s27)] ^ C[ 68+224]; + t5 = T0[B3(s25)] ^ T1[B2(s26)] ^ T2[B1(s27)] ^ T3[B0(s24)] ^ C[ 69+224]; + t9 = T0[B3(s26)] ^ T1[B2(s27)] ^ T2[B1(s24)] ^ T3[B0(s25)] ^ C[ 70+224]; + td = T0[B3(s27)] ^ T1[B2(s24)] ^ T2[B1(s25)] ^ T3[B0(s26)] ^ C[ 71+224]; + t2 = T0[B3(s28)] ^ T1[B2(s29)] ^ T2[B1(s2a)] ^ T3[B0(s2b)] ^ C[ 72+224]; + t6 = T0[B3(s29)] ^ T1[B2(s2a)] ^ T2[B1(s2b)] ^ T3[B0(s28)] ^ C[ 73+224]; + ta = T0[B3(s2a)] ^ T1[B2(s2b)] ^ T2[B1(s28)] ^ T3[B0(s29)] ^ C[ 74+224]; + te = T0[B3(s2b)] ^ T1[B2(s28)] ^ T2[B1(s29)] ^ T3[B0(s2a)] ^ C[ 75+224]; + t3 = T0[B3(s2c)] ^ T1[B2(s2d)] ^ T2[B1(s2e)] ^ T3[B0(s2f)] ^ C[ 76+224]; + t7 = T0[B3(s2d)] ^ T1[B2(s2e)] ^ T2[B1(s2f)] ^ T3[B0(s2c)] ^ C[ 77+224]; + tb = T0[B3(s2e)] ^ T1[B2(s2f)] ^ T2[B1(s2c)] ^ T3[B0(s2d)] ^ C[ 78+224]; + tf = T0[B3(s2f)] ^ T1[B2(s2c)] ^ T2[B1(s2d)] ^ T3[B0(s2e)] ^ C[ 79+224]; + + s20 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 80+224]; + s24 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 81+224]; + s28 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 82+224]; + s2c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 83+224] ^ ctrl; + s21 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 84+224]; + s25 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 85+224]; + s29 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 86+224]; + s2d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 87+224]; + s22 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 88+224]; + s26 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 89+224]; + s2a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 90+224]; + s2e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 91+224]; + s23 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 92+224]; + s27 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 93+224]; + s2b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 94+224]; + s2f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 95+224]; + + t0 = T0[B3(s20)] ^ T1[B2(s21)] ^ T2[B1(s22)] ^ T3[B0(s23)] ^ C[ 96+224]; + t4 = T0[B3(s21)] ^ T1[B2(s22)] ^ T2[B1(s23)] ^ T3[B0(s20)] ^ C[ 97+224]; + t8 = T0[B3(s22)] ^ T1[B2(s23)] ^ T2[B1(s20)] ^ T3[B0(s21)] ^ C[ 98+224]; + tc = T0[B3(s23)] ^ T1[B2(s20)] ^ T2[B1(s21)] ^ T3[B0(s22)] ^ C[ 99+224] ^ ctrh; + t1 = T0[B3(s24)] ^ T1[B2(s25)] ^ T2[B1(s26)] ^ T3[B0(s27)] ^ C[100+224]; + t5 = T0[B3(s25)] ^ T1[B2(s26)] ^ T2[B1(s27)] ^ T3[B0(s24)] ^ C[101+224]; + t9 = T0[B3(s26)] ^ T1[B2(s27)] ^ T2[B1(s24)] ^ T3[B0(s25)] ^ C[102+224]; + td = T0[B3(s27)] ^ T1[B2(s24)] ^ T2[B1(s25)] ^ T3[B0(s26)] ^ C[103+224]; + t2 = T0[B3(s28)] ^ T1[B2(s29)] ^ T2[B1(s2a)] ^ T3[B0(s2b)] ^ C[104+224]; + t6 = T0[B3(s29)] ^ T1[B2(s2a)] ^ T2[B1(s2b)] ^ T3[B0(s28)] ^ C[105+224]; + ta = T0[B3(s2a)] ^ T1[B2(s2b)] ^ T2[B1(s28)] ^ T3[B0(s29)] ^ C[106+224]; + te = T0[B3(s2b)] ^ T1[B2(s28)] ^ T2[B1(s29)] ^ T3[B0(s2a)] ^ C[107+224]; + t3 = T0[B3(s2c)] ^ T1[B2(s2d)] ^ T2[B1(s2e)] ^ T3[B0(s2f)] ^ C[108+224]; + t7 = T0[B3(s2d)] ^ T1[B2(s2e)] ^ T2[B1(s2f)] ^ T3[B0(s2c)] ^ C[109+224]; + tb = T0[B3(s2e)] ^ T1[B2(s2f)] ^ T2[B1(s2c)] ^ T3[B0(s2d)] ^ C[110+224]; + tf = T0[B3(s2f)] ^ T1[B2(s2c)] ^ T2[B1(s2d)] ^ T3[B0(s2e)] ^ C[111+224]; + + s60 ^= T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )]; + s64 ^= T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )]; + s68 ^= T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )]; + s6c ^= T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )]; + s61 ^= T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )]; + s65 ^= T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )]; + s69 ^= T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )]; + s6d ^= T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )]; + s62 ^= T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )]; + s66 ^= T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )]; + s6a ^= T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )]; + s6e ^= T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )]; + s63 ^= T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )]; + s67 ^= T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )]; + s6b ^= T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )]; + s6f ^= T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )]; + + /* Lane 3 */ + t0 = T0[B3(s30)] ^ T1[B2(s31)] ^ T2[B1(s32)] ^ T3[B0(s33)] ^ C[ 0+336]; + t4 = T0[B3(s31)] ^ T1[B2(s32)] ^ T2[B1(s33)] ^ T3[B0(s30)] ^ C[ 1+336]; + t8 = T0[B3(s32)] ^ T1[B2(s33)] ^ T2[B1(s30)] ^ T3[B0(s31)] ^ C[ 2+336]; + tc = T0[B3(s33)] ^ T1[B2(s30)] ^ T2[B1(s31)] ^ T3[B0(s32)] ^ C[ 3+336] ^ ctrl; + t1 = T0[B3(s34)] ^ T1[B2(s35)] ^ T2[B1(s36)] ^ T3[B0(s37)] ^ C[ 4+336]; + t5 = T0[B3(s35)] ^ T1[B2(s36)] ^ T2[B1(s37)] ^ T3[B0(s34)] ^ C[ 5+336]; + t9 = T0[B3(s36)] ^ T1[B2(s37)] ^ T2[B1(s34)] ^ T3[B0(s35)] ^ C[ 6+336]; + td = T0[B3(s37)] ^ T1[B2(s34)] ^ T2[B1(s35)] ^ T3[B0(s36)] ^ C[ 7+336]; + t2 = T0[B3(s38)] ^ T1[B2(s39)] ^ T2[B1(s3a)] ^ T3[B0(s3b)] ^ C[ 8+336]; + t6 = T0[B3(s39)] ^ T1[B2(s3a)] ^ T2[B1(s3b)] ^ T3[B0(s38)] ^ C[ 9+336]; + ta = T0[B3(s3a)] ^ T1[B2(s3b)] ^ T2[B1(s38)] ^ T3[B0(s39)] ^ C[ 10+336]; + te = T0[B3(s3b)] ^ T1[B2(s38)] ^ T2[B1(s39)] ^ T3[B0(s3a)] ^ C[ 11+336]; + t3 = T0[B3(s3c)] ^ T1[B2(s3d)] ^ T2[B1(s3e)] ^ T3[B0(s3f)] ^ C[ 12+336]; + t7 = T0[B3(s3d)] ^ T1[B2(s3e)] ^ T2[B1(s3f)] ^ T3[B0(s3c)] ^ C[ 13+336]; + tb = T0[B3(s3e)] ^ T1[B2(s3f)] ^ T2[B1(s3c)] ^ T3[B0(s3d)] ^ C[ 14+336]; + tf = T0[B3(s3f)] ^ T1[B2(s3c)] ^ T2[B1(s3d)] ^ T3[B0(s3e)] ^ C[ 15+336]; + + s30 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 16+336]; + s34 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 17+336]; + s38 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 18+336]; + s3c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 19+336] ^ ctrh; + s31 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 20+336]; + s35 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 21+336]; + s39 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 22+336]; + s3d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 23+336]; + s32 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 24+336]; + s36 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 25+336]; + s3a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 26+336]; + s3e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 27+336]; + s33 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 28+336]; + s37 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 29+336]; + s3b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 30+336]; + s3f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 31+336]; + + t0 = T0[B3(s30)] ^ T1[B2(s31)] ^ T2[B1(s32)] ^ T3[B0(s33)] ^ C[ 32+336]; + t4 = T0[B3(s31)] ^ T1[B2(s32)] ^ T2[B1(s33)] ^ T3[B0(s30)] ^ C[ 33+336]; + t8 = T0[B3(s32)] ^ T1[B2(s33)] ^ T2[B1(s30)] ^ T3[B0(s31)] ^ C[ 34+336]; + tc = T0[B3(s33)] ^ T1[B2(s30)] ^ T2[B1(s31)] ^ T3[B0(s32)] ^ C[ 35+336] ^ ctrl; + t1 = T0[B3(s34)] ^ T1[B2(s35)] ^ T2[B1(s36)] ^ T3[B0(s37)] ^ C[ 36+336]; + t5 = T0[B3(s35)] ^ T1[B2(s36)] ^ T2[B1(s37)] ^ T3[B0(s34)] ^ C[ 37+336]; + t9 = T0[B3(s36)] ^ T1[B2(s37)] ^ T2[B1(s34)] ^ T3[B0(s35)] ^ C[ 38+336]; + td = T0[B3(s37)] ^ T1[B2(s34)] ^ T2[B1(s35)] ^ T3[B0(s36)] ^ C[ 39+336]; + t2 = T0[B3(s38)] ^ T1[B2(s39)] ^ T2[B1(s3a)] ^ T3[B0(s3b)] ^ C[ 40+336]; + t6 = T0[B3(s39)] ^ T1[B2(s3a)] ^ T2[B1(s3b)] ^ T3[B0(s38)] ^ C[ 41+336]; + ta = T0[B3(s3a)] ^ T1[B2(s3b)] ^ T2[B1(s38)] ^ T3[B0(s39)] ^ C[ 42+336]; + te = T0[B3(s3b)] ^ T1[B2(s38)] ^ T2[B1(s39)] ^ T3[B0(s3a)] ^ C[ 43+336]; + t3 = T0[B3(s3c)] ^ T1[B2(s3d)] ^ T2[B1(s3e)] ^ T3[B0(s3f)] ^ C[ 44+336]; + t7 = T0[B3(s3d)] ^ T1[B2(s3e)] ^ T2[B1(s3f)] ^ T3[B0(s3c)] ^ C[ 45+336]; + tb = T0[B3(s3e)] ^ T1[B2(s3f)] ^ T2[B1(s3c)] ^ T3[B0(s3d)] ^ C[ 46+336]; + tf = T0[B3(s3f)] ^ T1[B2(s3c)] ^ T2[B1(s3d)] ^ T3[B0(s3e)] ^ C[ 47+336]; + + s30 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 48+336]; + s34 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 49+336]; + s38 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 50+336]; + s3c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 51+336] ^ ctrh; + s31 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 52+336]; + s35 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 53+336]; + s39 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 54+336]; + s3d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 55+336]; + s32 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 56+336]; + s36 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 57+336]; + s3a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 58+336]; + s3e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 59+336]; + s33 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 60+336]; + s37 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 61+336]; + s3b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 62+336]; + s3f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 63+336]; + + t0 = T0[B3(s30)] ^ T1[B2(s31)] ^ T2[B1(s32)] ^ T3[B0(s33)] ^ C[ 64+336]; + t4 = T0[B3(s31)] ^ T1[B2(s32)] ^ T2[B1(s33)] ^ T3[B0(s30)] ^ C[ 65+336]; + t8 = T0[B3(s32)] ^ T1[B2(s33)] ^ T2[B1(s30)] ^ T3[B0(s31)] ^ C[ 66+336]; + tc = T0[B3(s33)] ^ T1[B2(s30)] ^ T2[B1(s31)] ^ T3[B0(s32)] ^ C[ 67+336] ^ ctrl; + t1 = T0[B3(s34)] ^ T1[B2(s35)] ^ T2[B1(s36)] ^ T3[B0(s37)] ^ C[ 68+336]; + t5 = T0[B3(s35)] ^ T1[B2(s36)] ^ T2[B1(s37)] ^ T3[B0(s34)] ^ C[ 69+336]; + t9 = T0[B3(s36)] ^ T1[B2(s37)] ^ T2[B1(s34)] ^ T3[B0(s35)] ^ C[ 70+336]; + td = T0[B3(s37)] ^ T1[B2(s34)] ^ T2[B1(s35)] ^ T3[B0(s36)] ^ C[ 71+336]; + t2 = T0[B3(s38)] ^ T1[B2(s39)] ^ T2[B1(s3a)] ^ T3[B0(s3b)] ^ C[ 72+336]; + t6 = T0[B3(s39)] ^ T1[B2(s3a)] ^ T2[B1(s3b)] ^ T3[B0(s38)] ^ C[ 73+336]; + ta = T0[B3(s3a)] ^ T1[B2(s3b)] ^ T2[B1(s38)] ^ T3[B0(s39)] ^ C[ 74+336]; + te = T0[B3(s3b)] ^ T1[B2(s38)] ^ T2[B1(s39)] ^ T3[B0(s3a)] ^ C[ 75+336]; + t3 = T0[B3(s3c)] ^ T1[B2(s3d)] ^ T2[B1(s3e)] ^ T3[B0(s3f)] ^ C[ 76+336]; + t7 = T0[B3(s3d)] ^ T1[B2(s3e)] ^ T2[B1(s3f)] ^ T3[B0(s3c)] ^ C[ 77+336]; + tb = T0[B3(s3e)] ^ T1[B2(s3f)] ^ T2[B1(s3c)] ^ T3[B0(s3d)] ^ C[ 78+336]; + tf = T0[B3(s3f)] ^ T1[B2(s3c)] ^ T2[B1(s3d)] ^ T3[B0(s3e)] ^ C[ 79+336]; + + s30 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 80+336]; + s34 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 81+336]; + s38 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 82+336]; + s3c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 83+336] ^ ctrh; + s31 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 84+336]; + s35 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 85+336]; + s39 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 86+336]; + s3d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 87+336]; + s32 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 88+336]; + s36 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 89+336]; + s3a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 90+336]; + s3e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 91+336]; + s33 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 92+336]; + s37 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 93+336]; + s3b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 94+336]; + s3f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 95+336]; + + t0 = T0[B3(s30)] ^ T1[B2(s31)] ^ T2[B1(s32)] ^ T3[B0(s33)] ^ C[ 96+336]; + t4 = T0[B3(s31)] ^ T1[B2(s32)] ^ T2[B1(s33)] ^ T3[B0(s30)] ^ C[ 97+336]; + t8 = T0[B3(s32)] ^ T1[B2(s33)] ^ T2[B1(s30)] ^ T3[B0(s31)] ^ C[ 98+336]; + tc = T0[B3(s33)] ^ T1[B2(s30)] ^ T2[B1(s31)] ^ T3[B0(s32)] ^ C[ 99+336] ^ ctrl; + t1 = T0[B3(s34)] ^ T1[B2(s35)] ^ T2[B1(s36)] ^ T3[B0(s37)] ^ C[100+336]; + t5 = T0[B3(s35)] ^ T1[B2(s36)] ^ T2[B1(s37)] ^ T3[B0(s34)] ^ C[101+336]; + t9 = T0[B3(s36)] ^ T1[B2(s37)] ^ T2[B1(s34)] ^ T3[B0(s35)] ^ C[102+336]; + td = T0[B3(s37)] ^ T1[B2(s34)] ^ T2[B1(s35)] ^ T3[B0(s36)] ^ C[103+336]; + t2 = T0[B3(s38)] ^ T1[B2(s39)] ^ T2[B1(s3a)] ^ T3[B0(s3b)] ^ C[104+336]; + t6 = T0[B3(s39)] ^ T1[B2(s3a)] ^ T2[B1(s3b)] ^ T3[B0(s38)] ^ C[105+336]; + ta = T0[B3(s3a)] ^ T1[B2(s3b)] ^ T2[B1(s38)] ^ T3[B0(s39)] ^ C[106+336]; + te = T0[B3(s3b)] ^ T1[B2(s38)] ^ T2[B1(s39)] ^ T3[B0(s3a)] ^ C[107+336]; + t3 = T0[B3(s3c)] ^ T1[B2(s3d)] ^ T2[B1(s3e)] ^ T3[B0(s3f)] ^ C[108+336]; + t7 = T0[B3(s3d)] ^ T1[B2(s3e)] ^ T2[B1(s3f)] ^ T3[B0(s3c)] ^ C[109+336]; + tb = T0[B3(s3e)] ^ T1[B2(s3f)] ^ T2[B1(s3c)] ^ T3[B0(s3d)] ^ C[110+336]; + tf = T0[B3(s3f)] ^ T1[B2(s3c)] ^ T2[B1(s3d)] ^ T3[B0(s3e)] ^ C[111+336]; + + s70 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )]; + s74 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )]; + s78 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )]; + s7c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )]; + s71 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )]; + s75 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )]; + s79 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )]; + s7d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )]; + s72 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )]; + s76 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )]; + s7a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )]; + s7e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )]; + s73 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )]; + s77 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )]; + s7b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )]; + s7f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )]; + + /* Lane 4 */ + t0 = T0[B3(s40)] ^ T1[B2(s41)] ^ T2[B1(s42)] ^ T3[B0(s43)] ^ C[ 0+448]; + t4 = T0[B3(s41)] ^ T1[B2(s42)] ^ T2[B1(s43)] ^ T3[B0(s40)] ^ C[ 1+448]; + t8 = T0[B3(s42)] ^ T1[B2(s43)] ^ T2[B1(s40)] ^ T3[B0(s41)] ^ C[ 2+448]; + tc = T0[B3(s43)] ^ T1[B2(s40)] ^ T2[B1(s41)] ^ T3[B0(s42)] ^ C[ 3+448] ^ ctrh; + t1 = T0[B3(s44)] ^ T1[B2(s45)] ^ T2[B1(s46)] ^ T3[B0(s47)] ^ C[ 4+448]; + t5 = T0[B3(s45)] ^ T1[B2(s46)] ^ T2[B1(s47)] ^ T3[B0(s44)] ^ C[ 5+448]; + t9 = T0[B3(s46)] ^ T1[B2(s47)] ^ T2[B1(s44)] ^ T3[B0(s45)] ^ C[ 6+448]; + td = T0[B3(s47)] ^ T1[B2(s44)] ^ T2[B1(s45)] ^ T3[B0(s46)] ^ C[ 7+448]; + t2 = T0[B3(s48)] ^ T1[B2(s49)] ^ T2[B1(s4a)] ^ T3[B0(s4b)] ^ C[ 8+448]; + t6 = T0[B3(s49)] ^ T1[B2(s4a)] ^ T2[B1(s4b)] ^ T3[B0(s48)] ^ C[ 9+448]; + ta = T0[B3(s4a)] ^ T1[B2(s4b)] ^ T2[B1(s48)] ^ T3[B0(s49)] ^ C[ 10+448]; + te = T0[B3(s4b)] ^ T1[B2(s48)] ^ T2[B1(s49)] ^ T3[B0(s4a)] ^ C[ 11+448]; + t3 = T0[B3(s4c)] ^ T1[B2(s4d)] ^ T2[B1(s4e)] ^ T3[B0(s4f)] ^ C[ 12+448]; + t7 = T0[B3(s4d)] ^ T1[B2(s4e)] ^ T2[B1(s4f)] ^ T3[B0(s4c)] ^ C[ 13+448]; + tb = T0[B3(s4e)] ^ T1[B2(s4f)] ^ T2[B1(s4c)] ^ T3[B0(s4d)] ^ C[ 14+448]; + tf = T0[B3(s4f)] ^ T1[B2(s4c)] ^ T2[B1(s4d)] ^ T3[B0(s4e)] ^ C[ 15+448]; + + s40 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 16+448]; + s44 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 17+448]; + s48 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 18+448]; + s4c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 19+448] ^ ctrl; + s41 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 20+448]; + s45 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 21+448]; + s49 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 22+448]; + s4d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 23+448]; + s42 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 24+448]; + s46 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 25+448]; + s4a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 26+448]; + s4e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 27+448]; + s43 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 28+448]; + s47 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 29+448]; + s4b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 30+448]; + s4f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 31+448]; + + t0 = T0[B3(s40)] ^ T1[B2(s41)] ^ T2[B1(s42)] ^ T3[B0(s43)] ^ C[ 32+448]; + t4 = T0[B3(s41)] ^ T1[B2(s42)] ^ T2[B1(s43)] ^ T3[B0(s40)] ^ C[ 33+448]; + t8 = T0[B3(s42)] ^ T1[B2(s43)] ^ T2[B1(s40)] ^ T3[B0(s41)] ^ C[ 34+448]; + tc = T0[B3(s43)] ^ T1[B2(s40)] ^ T2[B1(s41)] ^ T3[B0(s42)] ^ C[ 35+448] ^ ctrh; + t1 = T0[B3(s44)] ^ T1[B2(s45)] ^ T2[B1(s46)] ^ T3[B0(s47)] ^ C[ 36+448]; + t5 = T0[B3(s45)] ^ T1[B2(s46)] ^ T2[B1(s47)] ^ T3[B0(s44)] ^ C[ 37+448]; + t9 = T0[B3(s46)] ^ T1[B2(s47)] ^ T2[B1(s44)] ^ T3[B0(s45)] ^ C[ 38+448]; + td = T0[B3(s47)] ^ T1[B2(s44)] ^ T2[B1(s45)] ^ T3[B0(s46)] ^ C[ 39+448]; + t2 = T0[B3(s48)] ^ T1[B2(s49)] ^ T2[B1(s4a)] ^ T3[B0(s4b)] ^ C[ 40+448]; + t6 = T0[B3(s49)] ^ T1[B2(s4a)] ^ T2[B1(s4b)] ^ T3[B0(s48)] ^ C[ 41+448]; + ta = T0[B3(s4a)] ^ T1[B2(s4b)] ^ T2[B1(s48)] ^ T3[B0(s49)] ^ C[ 42+448]; + te = T0[B3(s4b)] ^ T1[B2(s48)] ^ T2[B1(s49)] ^ T3[B0(s4a)] ^ C[ 43+448]; + t3 = T0[B3(s4c)] ^ T1[B2(s4d)] ^ T2[B1(s4e)] ^ T3[B0(s4f)] ^ C[ 44+448]; + t7 = T0[B3(s4d)] ^ T1[B2(s4e)] ^ T2[B1(s4f)] ^ T3[B0(s4c)] ^ C[ 45+448]; + tb = T0[B3(s4e)] ^ T1[B2(s4f)] ^ T2[B1(s4c)] ^ T3[B0(s4d)] ^ C[ 46+448]; + tf = T0[B3(s4f)] ^ T1[B2(s4c)] ^ T2[B1(s4d)] ^ T3[B0(s4e)] ^ C[ 47+448]; + + s40 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 48+448]; + s44 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 49+448]; + s48 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 50+448]; + s4c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 51+448] ^ ctrl; + s41 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 52+448]; + s45 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 53+448]; + s49 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 54+448]; + s4d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 55+448]; + s42 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 56+448]; + s46 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 57+448]; + s4a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 58+448]; + s4e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 59+448]; + s43 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 60+448]; + s47 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 61+448]; + s4b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 62+448]; + s4f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 63+448]; + + t0 = T0[B3(s40)] ^ T1[B2(s41)] ^ T2[B1(s42)] ^ T3[B0(s43)] ^ C[ 64+448]; + t4 = T0[B3(s41)] ^ T1[B2(s42)] ^ T2[B1(s43)] ^ T3[B0(s40)] ^ C[ 65+448]; + t8 = T0[B3(s42)] ^ T1[B2(s43)] ^ T2[B1(s40)] ^ T3[B0(s41)] ^ C[ 66+448]; + tc = T0[B3(s43)] ^ T1[B2(s40)] ^ T2[B1(s41)] ^ T3[B0(s42)] ^ C[ 67+448] ^ ctrh; + t1 = T0[B3(s44)] ^ T1[B2(s45)] ^ T2[B1(s46)] ^ T3[B0(s47)] ^ C[ 68+448]; + t5 = T0[B3(s45)] ^ T1[B2(s46)] ^ T2[B1(s47)] ^ T3[B0(s44)] ^ C[ 69+448]; + t9 = T0[B3(s46)] ^ T1[B2(s47)] ^ T2[B1(s44)] ^ T3[B0(s45)] ^ C[ 70+448]; + td = T0[B3(s47)] ^ T1[B2(s44)] ^ T2[B1(s45)] ^ T3[B0(s46)] ^ C[ 71+448]; + t2 = T0[B3(s48)] ^ T1[B2(s49)] ^ T2[B1(s4a)] ^ T3[B0(s4b)] ^ C[ 72+448]; + t6 = T0[B3(s49)] ^ T1[B2(s4a)] ^ T2[B1(s4b)] ^ T3[B0(s48)] ^ C[ 73+448]; + ta = T0[B3(s4a)] ^ T1[B2(s4b)] ^ T2[B1(s48)] ^ T3[B0(s49)] ^ C[ 74+448]; + te = T0[B3(s4b)] ^ T1[B2(s48)] ^ T2[B1(s49)] ^ T3[B0(s4a)] ^ C[ 75+448]; + t3 = T0[B3(s4c)] ^ T1[B2(s4d)] ^ T2[B1(s4e)] ^ T3[B0(s4f)] ^ C[ 76+448]; + t7 = T0[B3(s4d)] ^ T1[B2(s4e)] ^ T2[B1(s4f)] ^ T3[B0(s4c)] ^ C[ 77+448]; + tb = T0[B3(s4e)] ^ T1[B2(s4f)] ^ T2[B1(s4c)] ^ T3[B0(s4d)] ^ C[ 78+448]; + tf = T0[B3(s4f)] ^ T1[B2(s4c)] ^ T2[B1(s4d)] ^ T3[B0(s4e)] ^ C[ 79+448]; + + s40 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 80+448]; + s44 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 81+448]; + s48 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 82+448]; + s4c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 83+448] ^ ctrl; + s41 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 84+448]; + s45 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 85+448]; + s49 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 86+448]; + s4d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 87+448]; + s42 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 88+448]; + s46 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 89+448]; + s4a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 90+448]; + s4e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 91+448]; + s43 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 92+448]; + s47 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 93+448]; + s4b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 94+448]; + s4f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 95+448]; + + t0 = T0[B3(s40)] ^ T1[B2(s41)] ^ T2[B1(s42)] ^ T3[B0(s43)] ^ C[ 96+448]; + t4 = T0[B3(s41)] ^ T1[B2(s42)] ^ T2[B1(s43)] ^ T3[B0(s40)] ^ C[ 97+448]; + t8 = T0[B3(s42)] ^ T1[B2(s43)] ^ T2[B1(s40)] ^ T3[B0(s41)] ^ C[ 98+448]; + tc = T0[B3(s43)] ^ T1[B2(s40)] ^ T2[B1(s41)] ^ T3[B0(s42)] ^ C[ 99+448] ^ ctrh; + t1 = T0[B3(s44)] ^ T1[B2(s45)] ^ T2[B1(s46)] ^ T3[B0(s47)] ^ C[100+448]; + t5 = T0[B3(s45)] ^ T1[B2(s46)] ^ T2[B1(s47)] ^ T3[B0(s44)] ^ C[101+448]; + t9 = T0[B3(s46)] ^ T1[B2(s47)] ^ T2[B1(s44)] ^ T3[B0(s45)] ^ C[102+448]; + td = T0[B3(s47)] ^ T1[B2(s44)] ^ T2[B1(s45)] ^ T3[B0(s46)] ^ C[103+448]; + t2 = T0[B3(s48)] ^ T1[B2(s49)] ^ T2[B1(s4a)] ^ T3[B0(s4b)] ^ C[104+448]; + t6 = T0[B3(s49)] ^ T1[B2(s4a)] ^ T2[B1(s4b)] ^ T3[B0(s48)] ^ C[105+448]; + ta = T0[B3(s4a)] ^ T1[B2(s4b)] ^ T2[B1(s48)] ^ T3[B0(s49)] ^ C[106+448]; + te = T0[B3(s4b)] ^ T1[B2(s48)] ^ T2[B1(s49)] ^ T3[B0(s4a)] ^ C[107+448]; + t3 = T0[B3(s4c)] ^ T1[B2(s4d)] ^ T2[B1(s4e)] ^ T3[B0(s4f)] ^ C[108+448]; + t7 = T0[B3(s4d)] ^ T1[B2(s4e)] ^ T2[B1(s4f)] ^ T3[B0(s4c)] ^ C[109+448]; + tb = T0[B3(s4e)] ^ T1[B2(s4f)] ^ T2[B1(s4c)] ^ T3[B0(s4d)] ^ C[110+448]; + tf = T0[B3(s4f)] ^ T1[B2(s4c)] ^ T2[B1(s4d)] ^ T3[B0(s4e)] ^ C[111+448]; + + s70 ^= T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )]; + s74 ^= T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )]; + s78 ^= T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )]; + s7c ^= T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )]; + s71 ^= T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )]; + s75 ^= T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )]; + s79 ^= T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )]; + s7d ^= T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )]; + s72 ^= T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )]; + s76 ^= T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )]; + s7a ^= T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )]; + s7e ^= T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )]; + s73 ^= T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )]; + s77 ^= T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )]; + s7b ^= T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )]; + s7f ^= T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )]; + + /* Lane 5 */ + t0 = T0[B3(s50)] ^ T1[B2(s51)] ^ T2[B1(s52)] ^ T3[B0(s53)] ^ C[ 0+560]; + t4 = T0[B3(s51)] ^ T1[B2(s52)] ^ T2[B1(s53)] ^ T3[B0(s50)] ^ C[ 1+560]; + t8 = T0[B3(s52)] ^ T1[B2(s53)] ^ T2[B1(s50)] ^ T3[B0(s51)] ^ C[ 2+560]; + tc = T0[B3(s53)] ^ T1[B2(s50)] ^ T2[B1(s51)] ^ T3[B0(s52)] ^ C[ 3+560] ^ ctrl; + t1 = T0[B3(s54)] ^ T1[B2(s55)] ^ T2[B1(s56)] ^ T3[B0(s57)] ^ C[ 4+560]; + t5 = T0[B3(s55)] ^ T1[B2(s56)] ^ T2[B1(s57)] ^ T3[B0(s54)] ^ C[ 5+560]; + t9 = T0[B3(s56)] ^ T1[B2(s57)] ^ T2[B1(s54)] ^ T3[B0(s55)] ^ C[ 6+560]; + td = T0[B3(s57)] ^ T1[B2(s54)] ^ T2[B1(s55)] ^ T3[B0(s56)] ^ C[ 7+560]; + t2 = T0[B3(s58)] ^ T1[B2(s59)] ^ T2[B1(s5a)] ^ T3[B0(s5b)] ^ C[ 8+560]; + t6 = T0[B3(s59)] ^ T1[B2(s5a)] ^ T2[B1(s5b)] ^ T3[B0(s58)] ^ C[ 9+560]; + ta = T0[B3(s5a)] ^ T1[B2(s5b)] ^ T2[B1(s58)] ^ T3[B0(s59)] ^ C[ 10+560]; + te = T0[B3(s5b)] ^ T1[B2(s58)] ^ T2[B1(s59)] ^ T3[B0(s5a)] ^ C[ 11+560]; + t3 = T0[B3(s5c)] ^ T1[B2(s5d)] ^ T2[B1(s5e)] ^ T3[B0(s5f)] ^ C[ 12+560]; + t7 = T0[B3(s5d)] ^ T1[B2(s5e)] ^ T2[B1(s5f)] ^ T3[B0(s5c)] ^ C[ 13+560]; + tb = T0[B3(s5e)] ^ T1[B2(s5f)] ^ T2[B1(s5c)] ^ T3[B0(s5d)] ^ C[ 14+560]; + tf = T0[B3(s5f)] ^ T1[B2(s5c)] ^ T2[B1(s5d)] ^ T3[B0(s5e)] ^ C[ 15+560]; + + s50 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 16+560]; + s54 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 17+560]; + s58 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 18+560]; + s5c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 19+560] ^ ctrh; + s51 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 20+560]; + s55 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 21+560]; + s59 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 22+560]; + s5d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 23+560]; + s52 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 24+560]; + s56 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 25+560]; + s5a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 26+560]; + s5e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 27+560]; + s53 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 28+560]; + s57 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 29+560]; + s5b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 30+560]; + s5f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 31+560]; + + t0 = T0[B3(s50)] ^ T1[B2(s51)] ^ T2[B1(s52)] ^ T3[B0(s53)] ^ C[ 32+560]; + t4 = T0[B3(s51)] ^ T1[B2(s52)] ^ T2[B1(s53)] ^ T3[B0(s50)] ^ C[ 33+560]; + t8 = T0[B3(s52)] ^ T1[B2(s53)] ^ T2[B1(s50)] ^ T3[B0(s51)] ^ C[ 34+560]; + tc = T0[B3(s53)] ^ T1[B2(s50)] ^ T2[B1(s51)] ^ T3[B0(s52)] ^ C[ 35+560] ^ ctrl; + t1 = T0[B3(s54)] ^ T1[B2(s55)] ^ T2[B1(s56)] ^ T3[B0(s57)] ^ C[ 36+560]; + t5 = T0[B3(s55)] ^ T1[B2(s56)] ^ T2[B1(s57)] ^ T3[B0(s54)] ^ C[ 37+560]; + t9 = T0[B3(s56)] ^ T1[B2(s57)] ^ T2[B1(s54)] ^ T3[B0(s55)] ^ C[ 38+560]; + td = T0[B3(s57)] ^ T1[B2(s54)] ^ T2[B1(s55)] ^ T3[B0(s56)] ^ C[ 39+560]; + t2 = T0[B3(s58)] ^ T1[B2(s59)] ^ T2[B1(s5a)] ^ T3[B0(s5b)] ^ C[ 40+560]; + t6 = T0[B3(s59)] ^ T1[B2(s5a)] ^ T2[B1(s5b)] ^ T3[B0(s58)] ^ C[ 41+560]; + ta = T0[B3(s5a)] ^ T1[B2(s5b)] ^ T2[B1(s58)] ^ T3[B0(s59)] ^ C[ 42+560]; + te = T0[B3(s5b)] ^ T1[B2(s58)] ^ T2[B1(s59)] ^ T3[B0(s5a)] ^ C[ 43+560]; + t3 = T0[B3(s5c)] ^ T1[B2(s5d)] ^ T2[B1(s5e)] ^ T3[B0(s5f)] ^ C[ 44+560]; + t7 = T0[B3(s5d)] ^ T1[B2(s5e)] ^ T2[B1(s5f)] ^ T3[B0(s5c)] ^ C[ 45+560]; + tb = T0[B3(s5e)] ^ T1[B2(s5f)] ^ T2[B1(s5c)] ^ T3[B0(s5d)] ^ C[ 46+560]; + tf = T0[B3(s5f)] ^ T1[B2(s5c)] ^ T2[B1(s5d)] ^ T3[B0(s5e)] ^ C[ 47+560]; + + s50 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 48+560]; + s54 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 49+560]; + s58 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 50+560]; + s5c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 51+560] ^ ctrh; + s51 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 52+560]; + s55 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 53+560]; + s59 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 54+560]; + s5d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 55+560]; + s52 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 56+560]; + s56 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 57+560]; + s5a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 58+560]; + s5e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 59+560]; + s53 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 60+560]; + s57 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 61+560]; + s5b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 62+560]; + s5f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 63+560]; + + t0 = T0[B3(s50)] ^ T1[B2(s51)] ^ T2[B1(s52)] ^ T3[B0(s53)] ^ C[ 64+560]; + t4 = T0[B3(s51)] ^ T1[B2(s52)] ^ T2[B1(s53)] ^ T3[B0(s50)] ^ C[ 65+560]; + t8 = T0[B3(s52)] ^ T1[B2(s53)] ^ T2[B1(s50)] ^ T3[B0(s51)] ^ C[ 66+560]; + tc = T0[B3(s53)] ^ T1[B2(s50)] ^ T2[B1(s51)] ^ T3[B0(s52)] ^ C[ 67+560] ^ ctrl; + t1 = T0[B3(s54)] ^ T1[B2(s55)] ^ T2[B1(s56)] ^ T3[B0(s57)] ^ C[ 68+560]; + t5 = T0[B3(s55)] ^ T1[B2(s56)] ^ T2[B1(s57)] ^ T3[B0(s54)] ^ C[ 69+560]; + t9 = T0[B3(s56)] ^ T1[B2(s57)] ^ T2[B1(s54)] ^ T3[B0(s55)] ^ C[ 70+560]; + td = T0[B3(s57)] ^ T1[B2(s54)] ^ T2[B1(s55)] ^ T3[B0(s56)] ^ C[ 71+560]; + t2 = T0[B3(s58)] ^ T1[B2(s59)] ^ T2[B1(s5a)] ^ T3[B0(s5b)] ^ C[ 72+560]; + t6 = T0[B3(s59)] ^ T1[B2(s5a)] ^ T2[B1(s5b)] ^ T3[B0(s58)] ^ C[ 73+560]; + ta = T0[B3(s5a)] ^ T1[B2(s5b)] ^ T2[B1(s58)] ^ T3[B0(s59)] ^ C[ 74+560]; + te = T0[B3(s5b)] ^ T1[B2(s58)] ^ T2[B1(s59)] ^ T3[B0(s5a)] ^ C[ 75+560]; + t3 = T0[B3(s5c)] ^ T1[B2(s5d)] ^ T2[B1(s5e)] ^ T3[B0(s5f)] ^ C[ 76+560]; + t7 = T0[B3(s5d)] ^ T1[B2(s5e)] ^ T2[B1(s5f)] ^ T3[B0(s5c)] ^ C[ 77+560]; + tb = T0[B3(s5e)] ^ T1[B2(s5f)] ^ T2[B1(s5c)] ^ T3[B0(s5d)] ^ C[ 78+560]; + tf = T0[B3(s5f)] ^ T1[B2(s5c)] ^ T2[B1(s5d)] ^ T3[B0(s5e)] ^ C[ 79+560]; + + s50 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 80+560]; + s54 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 81+560]; + s58 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 82+560]; + s5c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 83+560] ^ ctrh; + s51 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 84+560]; + s55 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 85+560]; + s59 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 86+560]; + s5d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 87+560]; + s52 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 88+560]; + s56 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 89+560]; + s5a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 90+560]; + s5e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 91+560]; + s53 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 92+560]; + s57 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 93+560]; + s5b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 94+560]; + s5f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 95+560]; + + t0 = T0[B3(s50)] ^ T1[B2(s51)] ^ T2[B1(s52)] ^ T3[B0(s53)] ^ C[ 96+560]; + t4 = T0[B3(s51)] ^ T1[B2(s52)] ^ T2[B1(s53)] ^ T3[B0(s50)] ^ C[ 97+560]; + t8 = T0[B3(s52)] ^ T1[B2(s53)] ^ T2[B1(s50)] ^ T3[B0(s51)] ^ C[ 98+560]; + tc = T0[B3(s53)] ^ T1[B2(s50)] ^ T2[B1(s51)] ^ T3[B0(s52)] ^ C[ 99+560] ^ ctrl; + t1 = T0[B3(s54)] ^ T1[B2(s55)] ^ T2[B1(s56)] ^ T3[B0(s57)] ^ C[100+560]; + t5 = T0[B3(s55)] ^ T1[B2(s56)] ^ T2[B1(s57)] ^ T3[B0(s54)] ^ C[101+560]; + t9 = T0[B3(s56)] ^ T1[B2(s57)] ^ T2[B1(s54)] ^ T3[B0(s55)] ^ C[102+560]; + td = T0[B3(s57)] ^ T1[B2(s54)] ^ T2[B1(s55)] ^ T3[B0(s56)] ^ C[103+560]; + t2 = T0[B3(s58)] ^ T1[B2(s59)] ^ T2[B1(s5a)] ^ T3[B0(s5b)] ^ C[104+560]; + t6 = T0[B3(s59)] ^ T1[B2(s5a)] ^ T2[B1(s5b)] ^ T3[B0(s58)] ^ C[105+560]; + ta = T0[B3(s5a)] ^ T1[B2(s5b)] ^ T2[B1(s58)] ^ T3[B0(s59)] ^ C[106+560]; + te = T0[B3(s5b)] ^ T1[B2(s58)] ^ T2[B1(s59)] ^ T3[B0(s5a)] ^ C[107+560]; + t3 = T0[B3(s5c)] ^ T1[B2(s5d)] ^ T2[B1(s5e)] ^ T3[B0(s5f)] ^ C[108+560]; + t7 = T0[B3(s5d)] ^ T1[B2(s5e)] ^ T2[B1(s5f)] ^ T3[B0(s5c)] ^ C[109+560]; + tb = T0[B3(s5e)] ^ T1[B2(s5f)] ^ T2[B1(s5c)] ^ T3[B0(s5d)] ^ C[110+560]; + tf = T0[B3(s5f)] ^ T1[B2(s5c)] ^ T2[B1(s5d)] ^ T3[B0(s5e)] ^ C[111+560]; + + s70 ^= T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )]; + s74 ^= T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )]; + s78 ^= T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )]; + s7c ^= T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )]; + s71 ^= T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )]; + s75 ^= T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )]; + s79 ^= T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )]; + s7d ^= T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )]; + s72 ^= T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )]; + s76 ^= T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )]; + s7a ^= T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )]; + s7e ^= T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )]; + s73 ^= T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )]; + s77 ^= T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )]; + s7b ^= T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )]; + s7f ^= T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )]; + + /* Lane 6 */ + t0 = T0[B3(s60)] ^ T1[B2(s61)] ^ T2[B1(s62)] ^ T3[B0(s63)] ^ C[ 0+672]; + t4 = T0[B3(s61)] ^ T1[B2(s62)] ^ T2[B1(s63)] ^ T3[B0(s60)] ^ C[ 1+672]; + t8 = T0[B3(s62)] ^ T1[B2(s63)] ^ T2[B1(s60)] ^ T3[B0(s61)] ^ C[ 2+672]; + tc = T0[B3(s63)] ^ T1[B2(s60)] ^ T2[B1(s61)] ^ T3[B0(s62)] ^ C[ 3+672] ^ ctrh; + t1 = T0[B3(s64)] ^ T1[B2(s65)] ^ T2[B1(s66)] ^ T3[B0(s67)] ^ C[ 4+672]; + t5 = T0[B3(s65)] ^ T1[B2(s66)] ^ T2[B1(s67)] ^ T3[B0(s64)] ^ C[ 5+672]; + t9 = T0[B3(s66)] ^ T1[B2(s67)] ^ T2[B1(s64)] ^ T3[B0(s65)] ^ C[ 6+672]; + td = T0[B3(s67)] ^ T1[B2(s64)] ^ T2[B1(s65)] ^ T3[B0(s66)] ^ C[ 7+672]; + t2 = T0[B3(s68)] ^ T1[B2(s69)] ^ T2[B1(s6a)] ^ T3[B0(s6b)] ^ C[ 8+672]; + t6 = T0[B3(s69)] ^ T1[B2(s6a)] ^ T2[B1(s6b)] ^ T3[B0(s68)] ^ C[ 9+672]; + ta = T0[B3(s6a)] ^ T1[B2(s6b)] ^ T2[B1(s68)] ^ T3[B0(s69)] ^ C[ 10+672]; + te = T0[B3(s6b)] ^ T1[B2(s68)] ^ T2[B1(s69)] ^ T3[B0(s6a)] ^ C[ 11+672]; + t3 = T0[B3(s6c)] ^ T1[B2(s6d)] ^ T2[B1(s6e)] ^ T3[B0(s6f)] ^ C[ 12+672]; + t7 = T0[B3(s6d)] ^ T1[B2(s6e)] ^ T2[B1(s6f)] ^ T3[B0(s6c)] ^ C[ 13+672]; + tb = T0[B3(s6e)] ^ T1[B2(s6f)] ^ T2[B1(s6c)] ^ T3[B0(s6d)] ^ C[ 14+672]; + tf = T0[B3(s6f)] ^ T1[B2(s6c)] ^ T2[B1(s6d)] ^ T3[B0(s6e)] ^ C[ 15+672]; + + s60 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 16+672]; + s64 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 17+672]; + s68 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 18+672]; + s6c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 19+672] ^ ctrl; + s61 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 20+672]; + s65 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 21+672]; + s69 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 22+672]; + s6d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 23+672]; + s62 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 24+672]; + s66 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 25+672]; + s6a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 26+672]; + s6e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 27+672]; + s63 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 28+672]; + s67 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 29+672]; + s6b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 30+672]; + s6f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 31+672]; + + t0 = T0[B3(s60)] ^ T1[B2(s61)] ^ T2[B1(s62)] ^ T3[B0(s63)] ^ C[ 32+672]; + t4 = T0[B3(s61)] ^ T1[B2(s62)] ^ T2[B1(s63)] ^ T3[B0(s60)] ^ C[ 33+672]; + t8 = T0[B3(s62)] ^ T1[B2(s63)] ^ T2[B1(s60)] ^ T3[B0(s61)] ^ C[ 34+672]; + tc = T0[B3(s63)] ^ T1[B2(s60)] ^ T2[B1(s61)] ^ T3[B0(s62)] ^ C[ 35+672] ^ ctrh; + t1 = T0[B3(s64)] ^ T1[B2(s65)] ^ T2[B1(s66)] ^ T3[B0(s67)] ^ C[ 36+672]; + t5 = T0[B3(s65)] ^ T1[B2(s66)] ^ T2[B1(s67)] ^ T3[B0(s64)] ^ C[ 37+672]; + t9 = T0[B3(s66)] ^ T1[B2(s67)] ^ T2[B1(s64)] ^ T3[B0(s65)] ^ C[ 38+672]; + td = T0[B3(s67)] ^ T1[B2(s64)] ^ T2[B1(s65)] ^ T3[B0(s66)] ^ C[ 39+672]; + t2 = T0[B3(s68)] ^ T1[B2(s69)] ^ T2[B1(s6a)] ^ T3[B0(s6b)] ^ C[ 40+672]; + t6 = T0[B3(s69)] ^ T1[B2(s6a)] ^ T2[B1(s6b)] ^ T3[B0(s68)] ^ C[ 41+672]; + ta = T0[B3(s6a)] ^ T1[B2(s6b)] ^ T2[B1(s68)] ^ T3[B0(s69)] ^ C[ 42+672]; + te = T0[B3(s6b)] ^ T1[B2(s68)] ^ T2[B1(s69)] ^ T3[B0(s6a)] ^ C[ 43+672]; + t3 = T0[B3(s6c)] ^ T1[B2(s6d)] ^ T2[B1(s6e)] ^ T3[B0(s6f)] ^ C[ 44+672]; + t7 = T0[B3(s6d)] ^ T1[B2(s6e)] ^ T2[B1(s6f)] ^ T3[B0(s6c)] ^ C[ 45+672]; + tb = T0[B3(s6e)] ^ T1[B2(s6f)] ^ T2[B1(s6c)] ^ T3[B0(s6d)] ^ C[ 46+672]; + tf = T0[B3(s6f)] ^ T1[B2(s6c)] ^ T2[B1(s6d)] ^ T3[B0(s6e)] ^ C[ 47+672]; + + h[ 0] = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )]; + h[ 4] = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )]; + h[ 8] = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )]; + h[12] = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )]; + h[ 1] = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )]; + h[ 5] = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )]; + h[ 9] = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )]; + h[13] = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )]; + h[ 2] = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )]; + h[ 6] = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )]; + h[10] = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )]; + h[14] = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )]; + h[ 3] = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )]; + h[ 7] = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )]; + h[11] = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )]; + h[15] = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )]; + + /* Lane 7 */ + t0 = T0[B3(s70)] ^ T1[B2(s71)] ^ T2[B1(s72)] ^ T3[B0(s73)] ^ C[ 0+720]; + t4 = T0[B3(s71)] ^ T1[B2(s72)] ^ T2[B1(s73)] ^ T3[B0(s70)] ^ C[ 1+720]; + t8 = T0[B3(s72)] ^ T1[B2(s73)] ^ T2[B1(s70)] ^ T3[B0(s71)] ^ C[ 2+720]; + tc = T0[B3(s73)] ^ T1[B2(s70)] ^ T2[B1(s71)] ^ T3[B0(s72)] ^ C[ 3+720] ^ ctrl; + t1 = T0[B3(s74)] ^ T1[B2(s75)] ^ T2[B1(s76)] ^ T3[B0(s77)] ^ C[ 4+720]; + t5 = T0[B3(s75)] ^ T1[B2(s76)] ^ T2[B1(s77)] ^ T3[B0(s74)] ^ C[ 5+720]; + t9 = T0[B3(s76)] ^ T1[B2(s77)] ^ T2[B1(s74)] ^ T3[B0(s75)] ^ C[ 6+720]; + td = T0[B3(s77)] ^ T1[B2(s74)] ^ T2[B1(s75)] ^ T3[B0(s76)] ^ C[ 7+720]; + t2 = T0[B3(s78)] ^ T1[B2(s79)] ^ T2[B1(s7a)] ^ T3[B0(s7b)] ^ C[ 8+720]; + t6 = T0[B3(s79)] ^ T1[B2(s7a)] ^ T2[B1(s7b)] ^ T3[B0(s78)] ^ C[ 9+720]; + ta = T0[B3(s7a)] ^ T1[B2(s7b)] ^ T2[B1(s78)] ^ T3[B0(s79)] ^ C[ 10+720]; + te = T0[B3(s7b)] ^ T1[B2(s78)] ^ T2[B1(s79)] ^ T3[B0(s7a)] ^ C[ 11+720]; + t3 = T0[B3(s7c)] ^ T1[B2(s7d)] ^ T2[B1(s7e)] ^ T3[B0(s7f)] ^ C[ 12+720]; + t7 = T0[B3(s7d)] ^ T1[B2(s7e)] ^ T2[B1(s7f)] ^ T3[B0(s7c)] ^ C[ 13+720]; + tb = T0[B3(s7e)] ^ T1[B2(s7f)] ^ T2[B1(s7c)] ^ T3[B0(s7d)] ^ C[ 14+720]; + tf = T0[B3(s7f)] ^ T1[B2(s7c)] ^ T2[B1(s7d)] ^ T3[B0(s7e)] ^ C[ 15+720]; + + s70 = T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )] ^ C[ 16+720]; + s74 = T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )] ^ C[ 17+720]; + s78 = T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )] ^ C[ 18+720]; + s7c = T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )] ^ C[ 19+720] ^ ctrh; + s71 = T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )] ^ C[ 20+720]; + s75 = T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )] ^ C[ 21+720]; + s79 = T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )] ^ C[ 22+720]; + s7d = T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )] ^ C[ 23+720]; + s72 = T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )] ^ C[ 24+720]; + s76 = T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )] ^ C[ 25+720]; + s7a = T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )] ^ C[ 26+720]; + s7e = T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )] ^ C[ 27+720]; + s73 = T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )] ^ C[ 28+720]; + s77 = T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )] ^ C[ 29+720]; + s7b = T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )] ^ C[ 30+720]; + s7f = T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )] ^ C[ 31+720]; + + t0 = T0[B3(s70)] ^ T1[B2(s71)] ^ T2[B1(s72)] ^ T3[B0(s73)] ^ C[ 32+720]; + t4 = T0[B3(s71)] ^ T1[B2(s72)] ^ T2[B1(s73)] ^ T3[B0(s70)] ^ C[ 33+720]; + t8 = T0[B3(s72)] ^ T1[B2(s73)] ^ T2[B1(s70)] ^ T3[B0(s71)] ^ C[ 34+720]; + tc = T0[B3(s73)] ^ T1[B2(s70)] ^ T2[B1(s71)] ^ T3[B0(s72)] ^ C[ 35+720] ^ ctrl; + t1 = T0[B3(s74)] ^ T1[B2(s75)] ^ T2[B1(s76)] ^ T3[B0(s77)] ^ C[ 36+720]; + t5 = T0[B3(s75)] ^ T1[B2(s76)] ^ T2[B1(s77)] ^ T3[B0(s74)] ^ C[ 37+720]; + t9 = T0[B3(s76)] ^ T1[B2(s77)] ^ T2[B1(s74)] ^ T3[B0(s75)] ^ C[ 38+720]; + td = T0[B3(s77)] ^ T1[B2(s74)] ^ T2[B1(s75)] ^ T3[B0(s76)] ^ C[ 39+720]; + t2 = T0[B3(s78)] ^ T1[B2(s79)] ^ T2[B1(s7a)] ^ T3[B0(s7b)] ^ C[ 40+720]; + t6 = T0[B3(s79)] ^ T1[B2(s7a)] ^ T2[B1(s7b)] ^ T3[B0(s78)] ^ C[ 41+720]; + ta = T0[B3(s7a)] ^ T1[B2(s7b)] ^ T2[B1(s78)] ^ T3[B0(s79)] ^ C[ 42+720]; + te = T0[B3(s7b)] ^ T1[B2(s78)] ^ T2[B1(s79)] ^ T3[B0(s7a)] ^ C[ 43+720]; + t3 = T0[B3(s7c)] ^ T1[B2(s7d)] ^ T2[B1(s7e)] ^ T3[B0(s7f)] ^ C[ 44+720]; + t7 = T0[B3(s7d)] ^ T1[B2(s7e)] ^ T2[B1(s7f)] ^ T3[B0(s7c)] ^ C[ 45+720]; + tb = T0[B3(s7e)] ^ T1[B2(s7f)] ^ T2[B1(s7c)] ^ T3[B0(s7d)] ^ C[ 46+720]; + tf = T0[B3(s7f)] ^ T1[B2(s7c)] ^ T2[B1(s7d)] ^ T3[B0(s7e)] ^ C[ 47+720]; + + h[ 0] ^= T0[B3(t0 )] ^ T1[B2(t1 )] ^ T2[B1(t2 )] ^ T3[B0(t3 )]; + h[ 4] ^= T0[B3(t1 )] ^ T1[B2(t2 )] ^ T2[B1(t3 )] ^ T3[B0(t0 )]; + h[ 8] ^= T0[B3(t2 )] ^ T1[B2(t3 )] ^ T2[B1(t0 )] ^ T3[B0(t1 )]; + h[12] ^= T0[B3(t3 )] ^ T1[B2(t0 )] ^ T2[B1(t1 )] ^ T3[B0(t2 )]; + h[ 1] ^= T0[B3(t4 )] ^ T1[B2(t5 )] ^ T2[B1(t6 )] ^ T3[B0(t7 )]; + h[ 5] ^= T0[B3(t5 )] ^ T1[B2(t6 )] ^ T2[B1(t7 )] ^ T3[B0(t4 )]; + h[ 9] ^= T0[B3(t6 )] ^ T1[B2(t7 )] ^ T2[B1(t4 )] ^ T3[B0(t5 )]; + h[13] ^= T0[B3(t7 )] ^ T1[B2(t4 )] ^ T2[B1(t5 )] ^ T3[B0(t6 )]; + h[ 2] ^= T0[B3(t8 )] ^ T1[B2(t9 )] ^ T2[B1(ta )] ^ T3[B0(tb )]; + h[ 6] ^= T0[B3(t9 )] ^ T1[B2(ta )] ^ T2[B1(tb )] ^ T3[B0(t8 )]; + h[10] ^= T0[B3(ta )] ^ T1[B2(tb )] ^ T2[B1(t8 )] ^ T3[B0(t9 )]; + h[14] ^= T0[B3(tb )] ^ T1[B2(t8 )] ^ T2[B1(t9 )] ^ T3[B0(ta )]; + h[ 3] ^= T0[B3(tc )] ^ T1[B2(td )] ^ T2[B1(te )] ^ T3[B0(tf )]; + h[ 7] ^= T0[B3(td )] ^ T1[B2(te )] ^ T2[B1(tf )] ^ T3[B0(tc )]; + h[11] ^= T0[B3(te )] ^ T1[B2(tf )] ^ T2[B1(tc )] ^ T3[B0(td )]; + h[15] ^= T0[B3(tf )] ^ T1[B2(tc )] ^ T2[B1(td )] ^ T3[B0(te )]; +} + +HashReturn laneInit (hashState *state, int hashbitlen) +{ + if (hashbitlen != 224 && hashbitlen != 256 && hashbitlen != 384 && hashbitlen != 512) + return BAD_HASHBITLEN; + + state->hashbitlen = hashbitlen; + state->ctr = 0; + + switch (state->hashbitlen) { + case 224: + memcpy(state->h, iv224, 8*sizeof(u32)); + break; + case 256: default: + memcpy(state->h, iv256, 8*sizeof(u32)); + break; + case 384: + memcpy(state->h, iv384, 16*sizeof(u32)); + break; + case 512: + memcpy(state->h, iv512, 16*sizeof(u32)); + break; + } + + return SUCCESS; +} + +HashReturn laneUpdate (hashState *state, const BitSequence *data, DataLength databitlen) +{ + u64 buffill; + u64 bytes; + + switch (state->hashbitlen) { + case 224: case 256: default: + buffill = (state->ctr >> 3) & 0x3f; + bytes = databitlen >> 3; + + if (state->ctr & 0x7) + return BAD_DATABITLEN; /* Only the last call to Update() may contain a fractional byte */ + + /* Check if we have some stuff left in the buffer. If so, fill it, and process it */ + if (buffill) { + const u64 n = buffill + bytes > 64 ? 64-buffill : bytes; /* number of bytes to copy */ + memcpy(state->buffer + buffill, data, n); + state->ctr += n << 3; + if (buffill + n == 64) /* full buffer now */ + lane256_compress(state->buffer, state->h, MSB32(state->ctr), LSB32(state->ctr)); + data += n; + bytes -= n; + } + + /* Now process as many full blocks as we can directly from the input message */ + while (bytes >= 64) { + state->ctr += 64 << 3; + lane256_compress(data, state->h, MSB32(state->ctr), LSB32(state->ctr)); + data += 64; + bytes -= 64; + } + break; + + case 384: case 512: + buffill = (state->ctr >> 3) & 0x7f; + bytes = databitlen >> 3; + + if (state->ctr & 0x7) + return BAD_DATABITLEN; /* Only the last call to Update() may contain a fractional byte */ + + /* Check if we have some stuff left in the buffer. If so, fill it, and process it */ + if (buffill) { + const u64 n = buffill + bytes > 128 ? 128-buffill : bytes; /* number of bytes to copy */ + memcpy(state->buffer + buffill, data, n); + state->ctr += n << 3; + if (buffill + n == 128) /* full buffer now */ + lane512_compress(state->buffer, state->h, MSB32(state->ctr), LSB32(state->ctr)); + data += n; + bytes -= n; + } + + /* Now process as many full blocks as we can directly from the input message */ + while (bytes >= 128) { + state->ctr += 128 << 3; + lane512_compress(data, state->h, MSB32(state->ctr), LSB32(state->ctr)); + data += 128; + bytes -= 128; + } + break; + } + + /* And finally, save the last, incomplete message block */ + if (bytes || (databitlen & 0x7)) { + memcpy(state->buffer, data, databitlen & 0x7 ? bytes+1 : bytes); /* also copy partial byte */ + state->ctr += (bytes << 3) + (databitlen & 0x7); + } + + return SUCCESS; +} + +HashReturn laneFinal (hashState *state, BitSequence *hashval) +{ + + switch (state->hashbitlen) { + case 224: case 256: default: + /* do zero padding and compress last block, if there is some data in the buffer */ + if (state->ctr & 0x1ff) { + const u64 n = (((state->ctr & 0x1ff) - 1) >> 3) + 1; /* number of bytes in buffer that are (partially) filled */ + if (n < 64) + memset(state->buffer + n, 0, 64-n); + state->buffer[(state->ctr >> 3)&0x3f] &= ~(0xff >> (state->ctr & 0x7)); /* zero-pad partial byte */ + lane256_compress(state->buffer, state->h, MSB32(state->ctr), LSB32(state->ctr)); + } + + /* output transformation */ + memset(state->buffer, 0, 64); + state->buffer[0] = 0x00; /* flag byte 0x00: output transformation without seed */ + state->buffer[1] = T8(state->ctr >> 56); /* message length in big-endian */ + state->buffer[2] = T8(state->ctr >> 48); + state->buffer[3] = T8(state->ctr >> 40); + state->buffer[4] = T8(state->ctr >> 32); + state->buffer[5] = T8(state->ctr >> 24); + state->buffer[6] = T8(state->ctr >> 16); + state->buffer[7] = T8(state->ctr >> 8); + state->buffer[8] = T8(state->ctr >> 0); + lane256_compress(state->buffer, state->h, 0, 0); + + /* write back result */ + U32TO8_BIG(hashval, state->h[0]); + U32TO8_BIG(hashval+4, state->h[1]); + U32TO8_BIG(hashval+8, state->h[2]); + U32TO8_BIG(hashval+12, state->h[3]); + U32TO8_BIG(hashval+16, state->h[4]); + U32TO8_BIG(hashval+20, state->h[5]); + U32TO8_BIG(hashval+24, state->h[6]); + U32TO8_BIG(hashval+28, state->h[7]); + + break; + + case 384: case 512: + /* do zero padding and compress last block, if there is some data in the buffer */ + if (state->ctr & 0x3ff) { + const u64 n = (((state->ctr & 0x3ff) - 1) >> 3) + 1; /* number of bytes in buffer that are (partially) filled */ + if (n < 128) + memset(state->buffer + n, 0, 128-n); + state->buffer[(state->ctr >> 3)&0x7f] &= ~(0xff >> (state->ctr & 0x7)); /* zero-pad partial byte */ + lane512_compress(state->buffer, state->h, MSB32(state->ctr), LSB32(state->ctr)); + } + + /* output transformation */ + memset(state->buffer, 0, 128); + state->buffer[0] = 0x00; /* flag byte 0x00: output transformation without seed */ + state->buffer[1] = T8(state->ctr >> 56); /* message length in big-endian */ + state->buffer[2] = T8(state->ctr >> 48); + state->buffer[3] = T8(state->ctr >> 40); + state->buffer[4] = T8(state->ctr >> 32); + state->buffer[5] = T8(state->ctr >> 24); + state->buffer[6] = T8(state->ctr >> 16); + state->buffer[7] = T8(state->ctr >> 8); + state->buffer[8] = T8(state->ctr >> 0); + lane512_compress(state->buffer, state->h, 0, 0); + + /* write back result */ + U32TO8_BIG(hashval, state->h[0]); + U32TO8_BIG(hashval+4, state->h[1]); + U32TO8_BIG(hashval+8, state->h[2]); + U32TO8_BIG(hashval+12, state->h[3]); + U32TO8_BIG(hashval+16, state->h[4]); + U32TO8_BIG(hashval+20, state->h[5]); + U32TO8_BIG(hashval+24, state->h[6]); + U32TO8_BIG(hashval+28, state->h[7]); + U32TO8_BIG(hashval+32, state->h[8]); + U32TO8_BIG(hashval+36, state->h[9]); + U32TO8_BIG(hashval+40, state->h[10]); + U32TO8_BIG(hashval+44, state->h[11]); + U32TO8_BIG(hashval+48, state->h[12]); + U32TO8_BIG(hashval+52, state->h[13]); + U32TO8_BIG(hashval+56, state->h[14]); + U32TO8_BIG(hashval+60, state->h[15]); + + break; + } + + return SUCCESS; +} + +HashReturn laneHash (int hashbitlen, const BitSequence *data, DataLength databitlen, BitSequence *hashval) +{ + hashState state; + HashReturn hashReturn; + + if ((hashReturn = laneInit(&state, hashbitlen)) != SUCCESS) + return hashReturn; + if ((hashReturn = laneUpdate(&state, data, databitlen)) != SUCCESS) + return hashReturn; + if ((hashReturn = laneFinal(&state, hashval)) != SUCCESS) + return hashReturn; + return SUCCESS; +} diff --git a/src/Native/libmultihash/lane.h b/src/Native/libmultihash/lane.h new file mode 100644 index 000000000..1d935a171 --- /dev/null +++ b/src/Native/libmultihash/lane.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2008 Sebastiaan Indesteege + * + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Optimised ANSI-C implementation of LANE + */ + +#ifndef LANE_H +#define LANE_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#include + +typedef unsigned char BitSequence; +typedef unsigned long long DataLength; + +typedef enum { SUCCESS = 0, FAIL = 1, BAD_HASHBITLEN = 2, BAD_DATABITLEN = 3 } HashReturn; + +typedef unsigned char u8; +typedef unsigned int u32; +typedef unsigned long long u64; + +typedef struct { + int hashbitlen; + u64 ctr; + u32 h[16]; + u8 buffer[128]; +} hashState; + +HashReturn laneInit (hashState *state, int hashbitlen); +HashReturn laneUpdate (hashState *state, const BitSequence *data, DataLength databitlen); +HashReturn laneFinal (hashState *state, BitSequence *hashval); +HashReturn laneHash (int hashbitlen, const BitSequence *data, DataLength databitlen, BitSequence *hashval); + +#if defined(__cplusplus) +} +#endif + +#endif /* LANE_H */ diff --git a/src/Native/libmultihash/libmultihash.vcxproj b/src/Native/libmultihash/libmultihash.vcxproj index ffdd97e7c..7522da19d 100644 --- a/src/Native/libmultihash/libmultihash.vcxproj +++ b/src/Native/libmultihash/libmultihash.vcxproj @@ -201,6 +201,7 @@ + @@ -238,6 +239,7 @@ + @@ -262,6 +264,7 @@ + @@ -292,6 +295,7 @@ + @@ -312,6 +316,7 @@ + @@ -346,6 +351,7 @@ + diff --git a/src/Native/libmultihash/libmultihash.vcxproj.filters b/src/Native/libmultihash/libmultihash.vcxproj.filters index b008bae8f..0ec24faa2 100644 --- a/src/Native/libmultihash/libmultihash.vcxproj.filters +++ b/src/Native/libmultihash/libmultihash.vcxproj.filters @@ -293,6 +293,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + @@ -541,6 +550,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + diff --git a/src/Native/libmultihash/sha3/panama.c b/src/Native/libmultihash/sha3/panama.c new file mode 100644 index 000000000..2c864bff8 --- /dev/null +++ b/src/Native/libmultihash/sha3/panama.c @@ -0,0 +1,334 @@ +/* $Id: panama.c 216 2010-06-08 09:46:57Z tp $ */ +/* + * PANAMA implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "sph_panama.h" + +#define LVAR17(b) sph_u32 \ + b ## 0, b ## 1, b ## 2, b ## 3, b ## 4, b ## 5, \ + b ## 6, b ## 7, b ## 8, b ## 9, b ## 10, b ## 11, \ + b ## 12, b ## 13, b ## 14, b ## 15, b ## 16; + +#define LVARS \ + LVAR17(a) \ + LVAR17(g) \ + LVAR17(p) \ + LVAR17(t) + +#define M17(macro) do { \ + macro( 0, 1, 2, 4); \ + macro( 1, 2, 3, 5); \ + macro( 2, 3, 4, 6); \ + macro( 3, 4, 5, 7); \ + macro( 4, 5, 6, 8); \ + macro( 5, 6, 7, 9); \ + macro( 6, 7, 8, 10); \ + macro( 7, 8, 9, 11); \ + macro( 8, 9, 10, 12); \ + macro( 9, 10, 11, 13); \ + macro(10, 11, 12, 14); \ + macro(11, 12, 13, 15); \ + macro(12, 13, 14, 16); \ + macro(13, 14, 15, 0); \ + macro(14, 15, 16, 1); \ + macro(15, 16, 0, 2); \ + macro(16, 0, 1, 3); \ + } while (0) + +#define BUPDATE1(n0, n2) do { \ + sc->buffer[ptr24][n0] ^= sc->buffer[ptr31][n2]; \ + sc->buffer[ptr31][n2] ^= INW1(n2); \ + } while (0) + +#define BUPDATE do { \ + BUPDATE1(0, 2); \ + BUPDATE1(1, 3); \ + BUPDATE1(2, 4); \ + BUPDATE1(3, 5); \ + BUPDATE1(4, 6); \ + BUPDATE1(5, 7); \ + BUPDATE1(6, 0); \ + BUPDATE1(7, 1); \ + } while (0) + +#define RSTATE(n0, n1, n2, n4) (a ## n0 = sc->state[n0]) + +#define WSTATE(n0, n1, n2, n4) (sc->state[n0] = a ## n0) + +#define GAMMA(n0, n1, n2, n4) \ + (g ## n0 = a ## n0 ^ (a ## n1 | SPH_T32(~a ## n2))) + +#define PI_ALL do { \ + p0 = g0; \ + p1 = SPH_ROTL32( g7, 1); \ + p2 = SPH_ROTL32(g14, 3); \ + p3 = SPH_ROTL32( g4, 6); \ + p4 = SPH_ROTL32(g11, 10); \ + p5 = SPH_ROTL32( g1, 15); \ + p6 = SPH_ROTL32( g8, 21); \ + p7 = SPH_ROTL32(g15, 28); \ + p8 = SPH_ROTL32( g5, 4); \ + p9 = SPH_ROTL32(g12, 13); \ + p10 = SPH_ROTL32( g2, 23); \ + p11 = SPH_ROTL32( g9, 2); \ + p12 = SPH_ROTL32(g16, 14); \ + p13 = SPH_ROTL32( g6, 27); \ + p14 = SPH_ROTL32(g13, 9); \ + p15 = SPH_ROTL32( g3, 24); \ + p16 = SPH_ROTL32(g10, 8); \ + } while (0) + +#define THETA(n0, n1, n2, n4) \ + (t ## n0 = p ## n0 ^ p ## n1 ^ p ## n4) + +#define SIGMA_ALL do { \ + a0 = t0 ^ 1; \ + a1 = t1 ^ INW2(0); \ + a2 = t2 ^ INW2(1); \ + a3 = t3 ^ INW2(2); \ + a4 = t4 ^ INW2(3); \ + a5 = t5 ^ INW2(4); \ + a6 = t6 ^ INW2(5); \ + a7 = t7 ^ INW2(6); \ + a8 = t8 ^ INW2(7); \ + a9 = t9 ^ sc->buffer[ptr16][0]; \ + a10 = t10 ^ sc->buffer[ptr16][1]; \ + a11 = t11 ^ sc->buffer[ptr16][2]; \ + a12 = t12 ^ sc->buffer[ptr16][3]; \ + a13 = t13 ^ sc->buffer[ptr16][4]; \ + a14 = t14 ^ sc->buffer[ptr16][5]; \ + a15 = t15 ^ sc->buffer[ptr16][6]; \ + a16 = t16 ^ sc->buffer[ptr16][7]; \ + } while (0) + +#define PANAMA_STEP do { \ + unsigned ptr16, ptr24, ptr31; \ + \ + ptr24 = (ptr0 - 8) & 31; \ + ptr31 = (ptr0 - 1) & 31; \ + BUPDATE; \ + M17(GAMMA); \ + PI_ALL; \ + M17(THETA); \ + ptr16 = ptr0 ^ 16; \ + SIGMA_ALL; \ + ptr0 = ptr31; \ + } while (0) + +/* + * These macros are used to compute + */ +#define INC0 1 +#define INC1 2 +#define INC2 3 +#define INC3 4 +#define INC4 5 +#define INC5 6 +#define INC6 7 +#define INC7 8 + +/* + * Push data by blocks of 32 bytes. "pbuf" must be 32-bit aligned. Each + * iteration processes 32 data bytes; "num" contains the number of + * iterations. + */ +static void +panama_push(sph_panama_context *sc, const unsigned char *pbuf, size_t num) +{ + LVARS + unsigned ptr0; +#if SPH_LITTLE_FAST +#define INW1(i) sph_dec32le_aligned(pbuf + 4 * (i)) +#else + sph_u32 X_var[8]; +#define INW1(i) X_var[i] +#endif +#define INW2(i) INW1(i) + + M17(RSTATE); + ptr0 = sc->buffer_ptr; + while (num -- > 0) { +#if !SPH_LITTLE_FAST + int i; + + for (i = 0; i < 8; i ++) + X_var[i] = sph_dec32le_aligned(pbuf + 4 * (i)); +#endif + PANAMA_STEP; + pbuf = (const unsigned char *)pbuf + 32; + } + M17(WSTATE); + sc->buffer_ptr = ptr0; + +#undef INW1 +#undef INW2 +} + +/* + * Perform the "pull" operation repeatedly ("num" times). The hash output + * will be extracted from the state afterwards. + */ +static void +panama_pull(sph_panama_context *sc, unsigned num) +{ + LVARS + unsigned ptr0; +#define INW1(i) INW_H1(INC ## i) +#define INW_H1(i) INW_H2(i) +#define INW_H2(i) a ## i +#define INW2(i) sc->buffer[ptr4][i] + + M17(RSTATE); + ptr0 = sc->buffer_ptr; + while (num -- > 0) { + unsigned ptr4; + + ptr4 = (ptr0 + 4) & 31; + PANAMA_STEP; + } + M17(WSTATE); + +#undef INW1 +#undef INW_H1 +#undef INW_H2 +#undef INW2 +} + +/* see sph_panama.h */ +void +sph_panama_init(void *cc) +{ + sph_panama_context *sc; + + sc = cc; + /* + * This is not completely conformant, but "it will work + * everywhere". Initial state consists of zeroes everywhere. + * Conceptually, the sph_u32 type may have padding bits which + * must not be set to 0; but such an architecture remains to + * be seen. + */ + sc->data_ptr = 0; + memset(sc->buffer, 0, sizeof sc->buffer); + sc->buffer_ptr = 0; + memset(sc->state, 0, sizeof sc->state); +} + +#ifdef SPH_UPTR +static void +panama_short(void *cc, const void *data, size_t len) +#else +void +sph_panama(void *cc, const void *data, size_t len) +#endif +{ + sph_panama_context *sc; + unsigned current; + + sc = cc; + current = sc->data_ptr; + while (len > 0) { + unsigned clen; + + clen = (sizeof sc->data) - current; + if (clen > len) + clen = len; + memcpy(sc->data + current, data, clen); + data = (const unsigned char *)data + clen; + len -= clen; + current += clen; + if (current == sizeof sc->data) { + current = 0; + panama_push(sc, sc->data, 1); + } + } + sc->data_ptr = current; +} + +#ifdef SPH_UPTR +/* see sph_panama.h */ +void +sph_panama(void *cc, const void *data, size_t len) +{ + sph_panama_context *sc; + unsigned current; + size_t rlen; + + if (len < (2 * sizeof sc->data)) { + panama_short(cc, data, len); + return; + } + sc = cc; + current = sc->data_ptr; + if (current > 0) { + unsigned t; + + t = (sizeof sc->data) - current; + panama_short(sc, data, t); + data = (const unsigned char *)data + t; + len -= t; + } +#if !SPH_UNALIGNED + if (((SPH_UPTR)data & 3) != 0) { + panama_short(sc, data, len); + return; + } +#endif + panama_push(sc, data, len >> 5); + rlen = len & 31; + if (rlen > 0) + memcpy(sc->data, + (const unsigned char *)data + len - rlen, rlen); + sc->data_ptr = rlen; +} +#endif + +/* see sph_panama.h */ +void +sph_panama_close(void *cc, void *dst) +{ + sph_panama_context *sc; + unsigned current; + int i; + + sc = cc; + current = sc->data_ptr; + sc->data[current ++] = 0x01; + memset(sc->data + current, 0, (sizeof sc->data) - current); + panama_push(sc, sc->data, 1); + panama_pull(sc, 32); + for (i = 0; i < 8; i ++) + sph_enc32le((unsigned char *)dst + 4 * i, sc->state[i + 9]); + sph_panama_init(sc); +} diff --git a/src/Native/libmultihash/sha3/sph_panama.h b/src/Native/libmultihash/sha3/sph_panama.h new file mode 100644 index 000000000..4217995d9 --- /dev/null +++ b/src/Native/libmultihash/sha3/sph_panama.h @@ -0,0 +1,126 @@ +/* $Id: sph_panama.h 154 2010-04-26 17:00:24Z tp $ */ +/** + * PANAMA interface. + * + * PANAMA has been published in: J. Daemen and C. Clapp, "Fast Hashing + * and Stream Encryption with PANAMA", Fast Software Encryption - + * FSE'98, LNCS 1372, Springer (1998), pp. 60--74. + * + * PANAMA is not fully defined with regards to endianness and related + * topics. This implementation follows strict little-endian conventions: + *

    + *
  • Each 32-byte input block is split into eight 32-bit words, the + * first (leftmost) word being numbered 0.
  • + *
  • Each such 32-bit word is decoded from memory in little-endian + * convention.
  • + *
  • The additional padding bit equal to "1" is added by considering + * the least significant bit in a byte to come first; practically, this + * means that a single byte of value 0x01 is appended to the (byte-oriented) + * message, and then 0 to 31 bytes of value 0x00.
  • + *
  • The output consists of eight 32-bit words; the word numbered 0 is + * written first (in leftmost position) and it is encoded in little-endian + * convention. + *
+ * With these conventions, PANAMA is sometimes known as "PANAMA-LE". The + * PANAMA reference implementation uses our conventions for input, but + * prescribes no convention for output. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_panama.h + * @author Thomas Pornin + */ + +#ifndef SPH_PANAMA_H__ +#define SPH_PANAMA_H__ + +#if defined(__cplusplus) +extern "C" { +#endif + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for PANAMA. + */ +#define SPH_SIZE_panama 256 + +/** + * This structure is a context for PANAMA computations: it contains the + * intermediate values and some data from the last entered block. Once + * a PANAMA computation has been performed, the context can be reused for + * another computation. + * + * The contents of this structure are private. A running PANAMA computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char data[32]; /* first field, for alignment */ + unsigned data_ptr; + + sph_u32 buffer[32][8]; + unsigned buffer_ptr; + + sph_u32 state[17]; +#endif +} sph_panama_context; + +/** + * Initialize a PANAMA context. This process performs no memory allocation. + * + * @param cc the PANAMA context (pointer to a sph_panama_context) + */ +void sph_panama_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the PANAMA context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_panama(void *cc, const void *data, size_t len); + +/** + * Terminate the current PANAMA computation and output the result into the + * provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the PANAMA context + * @param dst the destination buffer + */ +void sph_panama_close(void *cc, void *dst); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/src/Native/libmultihash/x25x.c b/src/Native/libmultihash/x25x.c new file mode 100644 index 000000000..c0281843d --- /dev/null +++ b/src/Native/libmultihash/x25x.c @@ -0,0 +1,182 @@ +#include +#include +#include +#include + +#include "sha3/sph_blake.h" +#include "sha3/sph_blake2s.h" +#include "sha3/sph_bmw.h" +#include "sha3/sph_groestl.h" +#include "sha3/sph_jh.h" +#include "sha3/sph_keccak.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_luffa.h" +#include "sha3/sph_cubehash.h" +#include "sha3/sph_shavite.h" +#include "sha3/sph_simd.h" +#include "sha3/sph_echo.h" +#include "sha3/sph_hamsi.h" +#include "sha3/sph_fugue.h" +#include "sha3/sph_shabal.h" +#include "sha3/sph_whirlpool.h" +#include "sha3/sph_sha2.h" +#include "sha3/sph_haval.h" +#include "sha3/sph_tiger.h" +#include "lyra2.h" +#include "sha3/gost_streebog.h" +#include "sha3/SWIFFTX.h" +#include "sha3/sph_panama.h" +#include "lane.h" +#include "blake2s.h" + +#define blake2s_salt32(out, in, inlen, key32) blake2s(out, in, key32, 32, inlen, 32) /* neoscrypt */ +#define blake2s_simple(out, in, inlen) blake2s(out, in, NULL, 32, inlen, 0) + +typedef struct +{ + unsigned char hash[64]; +} uint512; + +void x25x_hash(const char* input, char* output, uint32_t len) +{ + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_skein512_context ctx_skein; + sph_luffa512_context ctx_luffa; + sph_cubehash512_context ctx_cubehash; + sph_shavite512_context ctx_shavite; + sph_simd512_context ctx_simd; + sph_echo512_context ctx_echo; + sph_hamsi512_context ctx_hamsi; + sph_fugue512_context ctx_fugue; + sph_shabal512_context ctx_shabal; + sph_whirlpool_context ctx_whirlpool; + sph_sha512_context ctx_sha2; + sph_haval256_5_context ctx_haval; + sph_tiger_context ctx_tiger; + sph_gost512_context ctx_gost; + sph_sha256_context ctx_sha; + sph_panama_context ctx_panama; + static unsigned char pblank[1]; + uint512 hash[25]; + + memset(&hash, 0, sizeof(hash)); + + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, input, len); + sph_blake512_close(&ctx_blake, (void*) &hash[0]); + + sph_bmw512_init(&ctx_bmw); + sph_bmw512(&ctx_bmw, (const void*) &hash[0], 64); + sph_bmw512_close(&ctx_bmw, (void*) &hash[1]); + + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, (const void*) &hash[1], 64); + sph_groestl512_close(&ctx_groestl, (void*) &hash[2]); + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, (const void*) &hash[2], 64); + sph_skein512_close(&ctx_skein, (void*) &hash[3]); + + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, (const void*) &hash[3], 64); + sph_jh512_close(&ctx_jh, (void*) &hash[4]); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, (const void*) &hash[4], 64); + sph_keccak512_close(&ctx_keccak, (void*) &hash[5]); + + sph_luffa512_init(&ctx_luffa); + sph_luffa512(&ctx_luffa, (void*) &hash[5], 64); + sph_luffa512_close(&ctx_luffa, (void*) &hash[6]); + + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512(&ctx_cubehash, (const void*) &hash[6], 64); + sph_cubehash512_close(&ctx_cubehash, (void*) &hash[7]); + + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, (const void*) &hash[7], 64); + sph_shavite512_close(&ctx_shavite, (void*) &hash[8]); + + sph_simd512_init(&ctx_simd); + sph_simd512(&ctx_simd, (const void*) &hash[8], 64); + sph_simd512_close(&ctx_simd, (void*) &hash[9]); + + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, (const void*) &hash[9], 64); + sph_echo512_close(&ctx_echo, (void*) &hash[10]); + + sph_hamsi512_init(&ctx_hamsi); + sph_hamsi512(&ctx_hamsi, (const void*) &hash[10], 64); + sph_hamsi512_close(&ctx_hamsi, (void*) &hash[11]); + + sph_fugue512_init(&ctx_fugue); + sph_fugue512(&ctx_fugue, (const void*) &hash[11], 64); + sph_fugue512_close(&ctx_fugue, (void*) &hash[12]); + + sph_shabal512_init(&ctx_shabal); + sph_shabal512(&ctx_shabal, (const void*) &hash[12], 64); + sph_shabal512_close(&ctx_shabal, (void*) &hash[13]); + + sph_whirlpool_init(&ctx_whirlpool); + sph_whirlpool(&ctx_whirlpool, (const void*) &hash[13], 64); + sph_whirlpool_close(&ctx_whirlpool, (void*) &hash[14]); + + sph_sha512_init(&ctx_sha2); + sph_sha512(&ctx_sha2, (const void*) &hash[14], 64); + sph_sha512_close(&ctx_sha2, (void*) &hash[15]); + + // Temporary var used by swifftx to manage 65 bytes output, + unsigned char temp[SWIFFTX_OUTPUT_BLOCK_SIZE] = { 0 }; + InitializeSWIFFTX(); + ComputeSingleSWIFFTX((unsigned char*)& hash[12], temp, false); + memcpy((unsigned char*)& hash[16], temp, 64); + + sph_haval256_5_init(&ctx_haval); + sph_haval256_5(&ctx_haval, (const void*) &hash[16], 64); + sph_haval256_5_close(&ctx_haval, (void*) &hash[17]); + + sph_tiger_init(&ctx_tiger); + sph_tiger(&ctx_tiger, (const void*) &hash[17], 64); + sph_tiger_close(&ctx_tiger, (void*) &hash[18]); + + LYRA2((void*) &hash[19], 32, (const void*) &hash[18], 32, (const void*) &hash[18], 32, 1, 4, 4); + + sph_gost512_init(&ctx_gost); + sph_gost512(&ctx_gost, (const void*) &hash[19], 64); + sph_gost512_close(&ctx_gost, (void*) &hash[20]); + + sph_sha256_init(&ctx_sha); + sph_sha256(&ctx_sha, (const void*) &hash[20], 64); + sph_sha256_close(&ctx_sha, (void*) &hash[21]); + + sph_panama_init(&ctx_panama); + sph_panama(&ctx_panama, (const void*) &hash[21], 64); + sph_panama_close(&ctx_panama, (void*) &hash[22]); + + laneHash(512, (BitSequence*)& hash[22], 512, (BitSequence*)& hash[23]); + + // simple shuffle algorithm +#define X25X_SHUFFLE_BLOCKS (24 /* number of algos so far */ * 64 /* output bytes per algo */ / 2 /* block size */) +#define X25X_SHUFFLE_ROUNDS 12 + static const uint16_t x25x_round_const[X25X_SHUFFLE_ROUNDS] = { + 0x142c, 0x5830, 0x678c, 0xe08c, + 0x3c67, 0xd50d, 0xb1d8, 0xecb2, + 0xd7ee, 0x6783, 0xfa6c, 0x4b9c + }; + + uint16_t * block_pointer = (uint16_t*)hash; + for (int r = 0; r < X25X_SHUFFLE_ROUNDS; r++) { + for (int i = 0; i < X25X_SHUFFLE_BLOCKS; i++) { + uint16_t block_value = block_pointer[X25X_SHUFFLE_BLOCKS - i - 1]; + block_pointer[i] ^= block_pointer[block_value % X25X_SHUFFLE_BLOCKS] + (x25x_round_const[r] << (i % 16)); + } + } + + blake2s_simple((uint8_t*) &hash[24], (void*) &hash[0], 64 * 24); + + memcpy(output, &hash[24], 32); +} diff --git a/src/Native/libmultihash/x25x.h b/src/Native/libmultihash/x25x.h new file mode 100644 index 000000000..d31834c0a --- /dev/null +++ b/src/Native/libmultihash/x25x.h @@ -0,0 +1,16 @@ +#ifndef X25X_H +#define X25X_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void x25x_hash(const char* input, char* output, uint32_t len); + +#ifdef __cplusplus +} +#endif + +#endif From b836e383f9f42c4368ca0f81ede2ab048f0fda70 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 20 May 2019 16:42:05 +0200 Subject: [PATCH 174/178] Cleanup/formatting pass --- src/Miningcore/Configuration/ClusterConfig.cs | 4 ++-- .../Postgres/Repositories/StatsRepository.cs | 2 +- src/Miningcore/Program.cs | 19 +++++++------------ 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index e831845a0..2ee4d0997 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -581,7 +581,7 @@ public partial class ApiRateLimitConfig public RateLimitRule[] Rules { get; set; } public string[] IpWhitelist { get; set; } } - + public class ApiSSLConfig { public bool Enabled { get; set; } @@ -596,7 +596,7 @@ public partial class ApiConfig public int Port { get; set; } public ApiSSLConfig SSLConfig { get; set; } - + public ApiRateLimitConfig RateLimiting { get; set; } /// diff --git a/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs index e5e86bb72..50f13484f 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs @@ -215,7 +215,7 @@ public async Task GetPoolMinerWorkerHashratesAsync(IDbCon " WHERE rk = 1" + ") s " + "WHERE s.hashrate > 0;"; - + return (await con.QueryAsync(query, new { poolId })) .ToArray(); } diff --git a/src/Miningcore/Program.cs b/src/Miningcore/Program.cs index 8d1075751..97f460a7c 100644 --- a/src/Miningcore/Program.cs +++ b/src/Miningcore/Program.cs @@ -735,14 +735,14 @@ private static void StartApi() options.SerializerSettings.Formatting = Formatting.Indented; }); + // Gzip Compression + services.AddResponseCompression(); + // Cors services.AddCors(); // WebSockets services.AddWebSocketManager(); - - // Gzip Compression - services.AddResponseCompression(); }) .Configure(app => { @@ -754,9 +754,7 @@ private static void StartApi() UseIpWhiteList(app, true, new[] { "/api/admin" }, clusterConfig.Api?.AdminIpWhitelist); UseIpWhiteList(app, true, new[] { "/metrics" }, clusterConfig.Api?.MetricsIpWhitelist); - // Gzip Compression app.UseResponseCompression(); - app.UseCors(builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials()); app.UseWebSockets(); app.MapWebSocketManager("/notifications", app.ApplicationServices.GetService()); @@ -765,14 +763,11 @@ private static void StartApi() }) .UseKestrel(options => { - if (clusterConfig.Api.SSLConfig?.Enabled == true) - options.Listen(address, clusterConfig.Api.Port, listenOptions => - { + options.Listen(address, clusterConfig.Api.Port, listenOptions => + { + if(clusterConfig.Api.SSLConfig?.Enabled == true) listenOptions.UseHttps(clusterConfig.Api.SSLConfig.SSLPath, clusterConfig.Api.SSLConfig.SSLPassword); - }); - else - options.Listen(address, clusterConfig.Api.Port); - + }); }) .Build(); From 3a77cfacaf8b126620f865aec2ca3acc97cb12ce Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 20 May 2019 17:05:05 +0200 Subject: [PATCH 175/178] PostgreSQL 11 instructions --- README.md | 23 +++++++++++++++++-- .../createdb_postgresql_11_appendix.sql | 18 +++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/Miningcore/Persistence/Postgres/Scripts/createdb_postgresql_11_appendix.sql diff --git a/README.md b/README.md index b907d2caa..f0e51459b 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ This software comes with a built-in donation of 0.1% per block-reward to support - Create a configuration file config.json as described [here](https://github.com/coinfoundry/miningcore/wiki/Configuration) - Run dotnet Miningcore.dll -c config.json -### PostgreSQL Database setup +### Basic PostgreSQL Database setup Create the database: @@ -82,7 +82,7 @@ $ createdb miningcore $ psql (enter the password for postgres) ``` -Run the query after login: +Inside psql execute: ```sql alter user miningcore with encrypted password 'some-secure-password'; @@ -96,6 +96,25 @@ $ wget https://raw.githubusercontent.com/coinfoundry/miningcore/master/src/Minin $ psql -d miningcore -U miningcore -f createdb.sql ``` +### Advanced PostgreSQL Database setup + +If you are planning to run a Multipool-Cluster, the simple setup might not perform well enough under high load. In this case you are strongly advised to use PostgreSQL 11 or higher. After performing the steps outlined in the basic setup above, perform these additional steps: + +**WARNING**: The following step will delete all recorded shares. Do **NOT** do this on a production pool! + +```console +$ wget https://raw.githubusercontent.com/coinfoundry/miningcore/master/src/Miningcore/Persistence/Postgres/Scripts/createdb_postgresql_11_appendix.sql +$ psql -d miningcore -U miningcore -f createdb_postgresql_11_appendix.sql +``` + +After executing the command, your shares table is now a list-partitioned table which dramatically improves query performance, since almost all database operations Miningcore performs are scoped to a certain pool. + +The following step needs to performed **once for every new pool*** you add to your cluster. Be sure to **replace all occurences** of mypool1 in the statement below with the id of your pool from your Miningcore configuration file: + +```sql +CREATE TABLE shares_mypool1 PARTITION OF shares FOR VALUES IN ('mypool1'); +``` + ### [Configuration](https://github.com/coinfoundry/miningcore/wiki/Configuration) ### [API](https://github.com/coinfoundry/miningcore/wiki/API) diff --git a/src/Miningcore/Persistence/Postgres/Scripts/createdb_postgresql_11_appendix.sql b/src/Miningcore/Persistence/Postgres/Scripts/createdb_postgresql_11_appendix.sql new file mode 100644 index 000000000..a76f61c73 --- /dev/null +++ b/src/Miningcore/Persistence/Postgres/Scripts/createdb_postgresql_11_appendix.sql @@ -0,0 +1,18 @@ +DROP TABLE shares; + +CREATE TABLE shares +( + poolid TEXT NOT NULL, + blockheight BIGINT NOT NULL, + difficulty DOUBLE PRECISION NOT NULL, + networkdifficulty DOUBLE PRECISION NOT NULL, + miner TEXT NOT NULL, + worker TEXT NULL, + useragent TEXT NULL, + ipaddress TEXT NOT NULL, + source TEXT NULL, + created TIMESTAMP NOT NULL +) PARTITION BY LIST (poolid); + +CREATE INDEX IDX_SHARES_CREATED ON SHARES(created); +CREATE INDEX IDX_SHARES_MINER_DIFFICULTY on SHARES(miner, difficulty); From 6de87b5b23bcb920e5db7356787ada5a0f5a42d1 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 20 May 2019 17:07:52 +0200 Subject: [PATCH 176/178] README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f0e51459b..05be83271 100644 --- a/README.md +++ b/README.md @@ -107,9 +107,9 @@ $ wget https://raw.githubusercontent.com/coinfoundry/miningcore/master/src/Minin $ psql -d miningcore -U miningcore -f createdb_postgresql_11_appendix.sql ``` -After executing the command, your shares table is now a list-partitioned table which dramatically improves query performance, since almost all database operations Miningcore performs are scoped to a certain pool. +After executing the command, your shares table is now a [list-partitioned table](https://www.postgresql.org/docs/11/ddl-partitioning.html) which dramatically improves query performance, since almost all database operations Miningcore performs are scoped to a certain pool. -The following step needs to performed **once for every new pool*** you add to your cluster. Be sure to **replace all occurences** of mypool1 in the statement below with the id of your pool from your Miningcore configuration file: +The following step needs to performed **once for every new pool** you add to your cluster. Be sure to **replace all occurences** of mypool1 in the statement below with the id of your pool from your Miningcore configuration file: ```sql CREATE TABLE shares_mypool1 PARTITION OF shares FOR VALUES IN ('mypool1'); From a687aab7932474af30c34670eb7b23ac024e348c Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 20 May 2019 17:34:02 +0200 Subject: [PATCH 177/178] Unix build fix --- src/Native/libmultihash/x25x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Native/libmultihash/x25x.c b/src/Native/libmultihash/x25x.c index c0281843d..9e812a759 100644 --- a/src/Native/libmultihash/x25x.c +++ b/src/Native/libmultihash/x25x.c @@ -22,7 +22,7 @@ #include "sha3/sph_sha2.h" #include "sha3/sph_haval.h" #include "sha3/sph_tiger.h" -#include "lyra2.h" +#include "Lyra2.h" #include "sha3/gost_streebog.h" #include "sha3/SWIFFTX.h" #include "sha3/sph_panama.h" From 2d7342dd25aa1155b5c3bdda27df7fbfaf2acbc1 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Mon, 20 May 2019 20:37:20 +0200 Subject: [PATCH 178/178] Fix db creation scripts --- src/Miningcore/Persistence/Postgres/Scripts/createdb.sql | 2 +- .../Postgres/Scripts/createdb_postgresql_11_appendix.sql | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql index 18c9cf350..b633483cd 100644 --- a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql +++ b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql @@ -1,4 +1,4 @@ -set role miningcore; +SET ROLE miningcore; CREATE TABLE shares ( diff --git a/src/Miningcore/Persistence/Postgres/Scripts/createdb_postgresql_11_appendix.sql b/src/Miningcore/Persistence/Postgres/Scripts/createdb_postgresql_11_appendix.sql index a76f61c73..6d2755b0b 100644 --- a/src/Miningcore/Persistence/Postgres/Scripts/createdb_postgresql_11_appendix.sql +++ b/src/Miningcore/Persistence/Postgres/Scripts/createdb_postgresql_11_appendix.sql @@ -1,3 +1,5 @@ +SET ROLE miningcore; + DROP TABLE shares; CREATE TABLE shares