diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index e60c80f42d..0000000000 --- a/.gitattributes +++ /dev/null @@ -1,192 +0,0 @@ -* text=auto - -###### Git -.gitattributes text -.gitignore text -.gitconfig text -.gitmodules text - -##### Windows -*.bat text eol=crlf -*.exe binary -*.dll binary - -##### Linux -*.sh text eol=lf -*.so binary - -##### Global -# Documents -*.sql text -*.md text -*.adoc text -*.textile text -*.mustache text -*.csv text -*.tab text -*.tsv text -*.coffee text -*.css text -*.htm text -*.html text -*.xhtml text -*.inc text -*.js text -*.jsx text -*.less text -*.od text -*.onlydata text -*.sass text -*.scm text -*.log text -*.properties text -*.scss text -*.styl text -*.tag text -*.ts text -*.tsx text -*.dockerignore text -Dockerfile text -*.markdown text -*.mdwn text -*.mdown text -*.mkd text -*.mkdn text -*.mdtxt text -*.mdtext text -*.txt text -AUTHORS text -CHANGELOG text -CHANGES text -CONTRIBUTING text -COPYING text -copyright text -*COPYRIGHT* text -INSTALL text -license text -LICENSE text -NEWS text -readme text -*README* text -TODO text -# Configuration -*.cnf text -*.cfg text -*.conf text -*.config text -*.ini text -*.json text -*.xml text -*.bowerrc text -.browserslistrc text -.editorconfig text -*.npmignore text -*.yaml text -*.yml text -browserslist text -Makefile text -makefile text -Procfile text -.slugignore text -# Linters -.csslintrc text -.eslintrc text -.htmlhintrc text -.jscsrc text -.jshintrc text -.jshintignore text -.stylelintrc text -# Video -*.3gpp binary -*.3gp binary -*.as binary -*.asf binary -*.asx binary -*.fla binary -*.flv binary -*.m4v binary -*.mng binary -*.mov binary -*.mp4 binary -*.mpeg binary -*.mpg binary -*.ogv binary -*.swc binary -*.swf binary -*.webm binary -# Audio -*.kar binary -*.m4a binary -*.mid binary -*.midi binary -*.mp3 binary -*.ogg binary -*.ra binary -# Graphics -*.png binary -*.jpg binary -*.jpeg binary -*.gif binary -*.tif binary -*.tiff binary -*.ico binary -*.eps binary -*.ai binary -*.bmp binary -*.jng binary -*.jp2 binary -*.jpx binary -*.jxr binary -*.pdf binary -*.psb binary -*.psd binary -*.svg text -*.svgz binary -*.wbmp binary -*.webp binary -# Archives -*.7z binary -*.gz binary -*.jar binary -*.rar binary -*.tar binary -*.zip binary -# Fonts -*.ttf binary -*.eot binary -*.otf binary -*.woff binary -*.woff2 binary -# Executables -*.pyc binary -# Objects -*.o binary - -##### IDE/Editor -# Visual Studio -*.sln text eol=crlf -*.csproj text eol=crlf -*.vbproj text eol=crlf -*.vcxproj text eol=crlf -*.vcproj text eol=crlf -*.dbproj text eol=crlf -*.fsproj text eol=crlf -*.lsproj text eol=crlf -*.wixproj text eol=crlf -*.modelproj text eol=crlf -*.sqlproj text eol=crlf -*.wmaproj text eol=crlf -*.xproj text eol=crlf -*.props text eol=crlf -*.filters text eol=crlf -*.vcxitems text eol=crlf - -##### Language -# .Net -*.resx text -*.settings text -*.cs text -*.vb text -*.cpp text -*.h text -*.fs text \ No newline at end of file diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 0bf0b0de53..0000000000 --- a/.gitignore +++ /dev/null @@ -1,214 +0,0 @@ -*.suo -*.user -*.sln.docstates -.vs/ -.vscode/ - -[Dd]ebug/ -[Rr]elease/ -x64/ -build/ -[Bb]in/ -[Oo]bj/ -*.VC.db -*.VC.opendb - -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -*_i.c -*_p.c -*.ilk -*.meta -*.obj -*.o -*.so -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.log -*.scc - -ipch/ -*.aps -*.ncb -*.opensdf -*.sdf -*.cachefile - -*.psess -*.vsp -*.vspx - -*.gpState - -_ReSharper*/ -*.[Rr]e[Ss]harper - -_TeamCity* - -*.dotCover - -*.ncrunch* -.*crunch*.local.xml - -[Ee]xpress/ - -*.Publish.xml -*.pubxml.user - -project.lock.json - -csx -*.build.csdef - -# Others -sql/ -*.Cache -ClientBin/ -[Ss]tyle[Cc]op.* -~$* -*~ -*.dbmdl -*.[Pp]ublish.xml -*.pfx -*.publishsettings - -# SQL Server files -App_Data/*.mdf -App_Data/*.ldf - -############# -## Windows detritus -############# - -# Windows image file caches -Thumbs.db -ehthumbs.db - -# Folder config file -Desktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Mac crap -.DS_Store - -############# -## Ignore Logs -############# - -logs/ - -src/Miningcore/config.json -src/Miningcore/config2.json -/src/Miningcore/coins2.json - -!**/lib/**/* - -# Created by https://www.toptal.com/developers/gitignore/api/rider -# Edit at https://www.toptal.com/developers/gitignore?templates=rider - -### Rider ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# AWS User-specific -.idea/**/aws.xml - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# SonarLint plugin -.idea/sonarlint/ - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -# End of https://www.toptal.com/developers/gitignore/api/rider -.idea - -.fake -/nbproject/ -/*/*/*/*.a -/*/*/*/*/*/*/*/*.o -/*/*/*/*/*/*/*/*/*.o -/*/*/*/*/*/*/*/*/*/*.o -/*/*/*/*/*/*/*/*/*/*.o diff --git a/Dockerfile b/Dockerfile index 0075e3412e..2803545634 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM mcr.microsoft.com/dotnet/sdk:6.0-jammy as BUILDER WORKDIR /app RUN apt-get update && \ - apt-get -y install cmake ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 libzmq3-dev golang-go libgmp-dev + apt-get -y install cmake clang ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 libzmq3-dev golang-go libgmp-dev libc++-dev zlib1g-dev COPY . . WORKDIR /app/src/Miningcore RUN dotnet publish -c Release --framework net6.0 -o ../../build diff --git a/README.md b/README.md index 5b67d43bcd..0216dbc850 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![Build status](https://ci.appveyor.com/api/projects/status/nbvaa55gu3icd1q8?svg=true)](https://ci.appveyor.com/project/oliverw/miningcore) -[![.NET](https://github.com/Kudaraidee/miningcore/actions/workflows/dotnet.yml/badge.svg)](https://github.com/blackmennewstyle/miningcore/actions/workflows/dotnet.yml) +[![.NET](https://github.com/blackmennewstyle/miningcore/actions/workflows/dotnet.yml/badge.svg)](https://github.com/blackmennewstyle/miningcore/actions/workflows/dotnet.yml) [![license](https://img.shields.io/github/license/mashape/apistatus.svg)]() @@ -83,14 +83,14 @@ cd miningcore Then build using Docker: ```console -docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:6.0 /bin/bash -c 'apt update && apt install cmake ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5n libzmq3-dev golang-go libgmp-dev -y --no-install-recommends && cd src/Miningcore && dotnet publish -c Release --framework net6.0 -o /app/build/' +docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:6.0 /bin/bash -c 'apt update && apt install cmake clang ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 libzmq3-dev golang-go libgmp-dev libc++-dev zlib1g-dev -y --no-install-recommends && cd src/Miningcore && dotnet publish -c Release --framework net6.0 -o /app/build/' ``` It will use a Linux container, you will build a Linux executable that will not run on Windows or macOS. You can use a runtime argument (-r) to specify the type of assets that you want to publish (if they don't match the SDK container). The following examples assume you want assets that match your host operating system, and use runtime arguments to ensure that. For macOS: ```console -docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:6.0 /bin/bash -c 'apt update && apt install cmake ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5n libzmq3-dev golang-go libgmp-dev -y --no-install-recommends && cd src/Miningcore && dotnet publish -c Release --framework net6.0 -o /app/build/ -r osx-x64 --self-contained false' +docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:6.0 /bin/bash -c 'apt update && apt install cmake clang ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 libzmq3-dev golang-go libgmp-dev libc++-dev zlib1g-dev -y --no-install-recommends && cd src/Miningcore && dotnet publish -c Release --framework net6.0 -o /app/build/ -r osx-x64 --self-contained false' ``` ### Building and Running Miningcore from a container @@ -121,7 +121,7 @@ docker run -d \ For Windows using Linux container: ```console -docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:6.0 /bin/bash -c 'apt update && apt install cmake ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5n libzmq3-dev golang-go libgmp-dev -y --no-install-recommends && cd src/Miningcore && dotnet publish -c Release --framework net6.0 -o /app/build/ -r win-x64 --self-contained false' +docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:6.0 /bin/bash -c 'apt update && apt install cmake clang ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 libzmq3-dev golang-go libgmp-dev libc++-dev zlib1g-dev -y --no-install-recommends && cd src/Miningcore && dotnet publish -c Release --framework net6.0 -o /app/build/ -r win-x64 --self-contained false' ``` To delete used images and containers you can run after all: @@ -239,4 +239,8 @@ To support this project you can become a [sponsor]( https://github.com/sponsors/ * CCX: `ccx7S4B3gBeH1SGWCfqZp3NM7Vavg7H3S8ovJn8fU4bwC4vU7ChWfHtbNzifhrpbJ74bMDxj4KZFTcznTfsucCEg1Kgv7zbNgs` * FIRO: `a5AsoTSkfPHQ3SUmR6binG1XW7oQQoFNU1` * ERGO: `9gYyuZzaSw3TiCtUkSRuS3XVDUv41EFs3dtNCFGqiEwHqpb7gkF` +* WART: `7795fc0fe93e7e4e232a212f00bdc8885c580a5666d39a0d` * XMR: `483zaHtMRfM7rw1dXgebhWaRR8QLgAF6w4BomAV319FVVHfdbYTLVuBRc4pQgRAnRpfy6CXvvwngK4Lo3mRKE29RRx3Jb5c` +* XEL: `xel:ajnsfv065qusndt0hfsngecrnf5690drmqmc0uq0etlx8zjlcyzqq2slgvt` +* CTXC: `0xbb60200d5151a4a0f9a75014e04cf61a0a9f0daf` +* ZANO: `ZxDKT1aqiEXPA5cDADtYEfMR1oXsRd68bby4nzUvVmnjHzzrfvjwhNdQ9yiWNeGutzg9LZdwsbP2FGB1gNpZXiYY1fCfpw33c` diff --git a/build-debian-11.sh b/build-debian-11.sh index 87b3f46d5e..16e767839c 100755 --- a/build-debian-11.sh +++ b/build-debian-11.sh @@ -5,13 +5,13 @@ sudo apt-get update; \ sudo apt-get -y install wget # add dotnet repo -sudo wget https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb -O packages-microsoft-prod.deb +wget https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb -O packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb rm packages-microsoft-prod.deb # install dev-dependencies sudo apt-get update; \ - sudo apt-get -y install dotnet-sdk-6.0 git cmake ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5-dev libgmp-dev + sudo apt-get -y install dotnet-sdk-6.0 git cmake clang ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5-dev libgmp-dev libc++-dev zlib1g-dev (cd src/Miningcore && \ BUILDIR=${1:-../../build} && \ diff --git a/build-debian-12.sh b/build-debian-12.sh index 4ed7c3e29a..ea0640cd97 100755 --- a/build-debian-12.sh +++ b/build-debian-12.sh @@ -5,13 +5,13 @@ sudo apt-get update; \ sudo apt-get -y install wget # add dotnet repo -sudo wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb +wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb rm packages-microsoft-prod.deb # install dev-dependencies sudo apt-get update; \ - sudo apt-get -y install dotnet-sdk-6.0 git cmake ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5-dev libgmp-dev + sudo apt-get -y install dotnet-sdk-6.0 git cmake clang ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5-dev libgmp-dev libc++-dev zlib1g-dev (cd src/Miningcore && \ BUILDIR=${1:-../../build} && \ diff --git a/build-ubuntu-20.04.sh b/build-ubuntu-20.04.sh index e0d5145925..279d15a99d 100755 --- a/build-ubuntu-20.04.sh +++ b/build-ubuntu-20.04.sh @@ -11,7 +11,7 @@ rm packages-microsoft-prod.deb # install dev-dependencies sudo apt-get update; \ - sudo apt-get -y install dotnet-sdk-6.0 git cmake ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 libgmp-dev + sudo apt-get -y install dotnet-sdk-6.0 git cmake clang ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 libgmp-dev libc++-dev zlib1g-dev (cd src/Miningcore && \ BUILDIR=${1:-../../build} && \ diff --git a/build-ubuntu-21.04.sh b/build-ubuntu-21.04.sh index c377bfff59..ebd59a4573 100755 --- a/build-ubuntu-21.04.sh +++ b/build-ubuntu-21.04.sh @@ -11,7 +11,7 @@ rm packages-microsoft-prod.deb # install dev-dependencies sudo apt-get update; \ - sudo apt-get -y install dotnet-sdk-6.0 git cmake ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 libgmp-dev + sudo apt-get -y install dotnet-sdk-6.0 git cmake clang ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 libgmp-dev libc++-dev zlib1g-dev (cd src/Miningcore && \ BUILDIR=${1:-../../build} && \ diff --git a/build-ubuntu-22.04.sh b/build-ubuntu-22.04.sh index b77ad6e3c5..aab6aadfdb 100755 --- a/build-ubuntu-22.04.sh +++ b/build-ubuntu-22.04.sh @@ -4,7 +4,7 @@ # install dev-dependencies sudo apt-get update; \ - sudo apt-get -y install dotnet6 git cmake ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 libgmp-dev + sudo apt-get -y install dotnet-sdk-6.0 git cmake clang ninja-build build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 libgmp-dev libc++-dev zlib1g-dev (cd src/Miningcore && \ BUILDIR=${1:-../../build} && \ diff --git a/build-windows.bat b/build-windows.bat index 87268cf1a6..f666e4608c 100644 --- a/build-windows.bat +++ b/build-windows.bat @@ -1,3 +1,3 @@ -@echo off -cd src\Miningcore -dotnet publish -c Release --framework net6.0 -o ../../build +@echo off +cd src\Miningcore +dotnet publish -c Release --framework net6.0 -o ../../build diff --git a/examples/alephium_pool.json b/examples/alephium_pool.json index 394cc70bfb..04e8aeaade 100644 --- a/examples/alephium_pool.json +++ b/examples/alephium_pool.json @@ -74,6 +74,7 @@ "percentage": 1 } ], + "enableAsicBoost": true, "clientConnectionTimeout": 600, "socketJobMessageBufferSize": 16384, "banning": { diff --git a/examples/arqma_pool.json b/examples/arqma_pool.json deleted file mode 100644 index 49ad9cecc0..0000000000 --- a/examples/arqma_pool.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "logging": - { - "level": "info", - "enableConsoleLog": true, - "enableConsoleColors": true, - "logFile": "", - "apiLogFile": "", - "logBaseDirectory": "", - "perPoolLogFile": false - }, - "banning": - { - "manager": "Integrated", - "banOnJunkReceive": true, - "banOnInvalidShares": false - }, - "notifications": - { - "enabled": false, - "email": - { - "host": "smtp.example.com", - "port": 587, - "user": "user", - "password": "password", - "fromAddress": "info@yourpool.org", - "fromName": "support" - }, - "admin": - { - "enabled": false, - "emailAddress": "user@example.com", - "notifyBlockFound": true - } - }, - "persistence": - { - "postgres": - { - "host": "127.0.0.1", - "port": 5432, - "user": "miningcore", - "password": "password", - "database": "miningcore" - } - }, - "paymentProcessing": - { - "enabled": true, - "interval": 600, - "shareRecoveryFile": "recovered-shares.txt" - }, - "api": - { - "enabled": true, - "listenAddress": "*", - "port": 4000, - "metricsIpWhitelist": [], - "rateLimiting": - { - "disabled": true, - "rules": - [ - { - "Endpoint": "*", - "Period": "1s", - "Limit": 5 - } - ], - "ipWhitelist": - [ - "" - ] - } - }, - "pools": - [ - { - "id": "arqma", - "enabled": true, - "coin": "zephyr", - "randomXRealm": "arqma", - "address": "ar2dDEehonEYXkJkXyZGNxAZhU8vFKmrtPKgebmKDpMvYz8YPjiRztfR5WMWpH8u6MCqsVpqnJ5bh5VVgP2Sw1Xh2iWsqC4ro", - "rewardRecipients": - [ - { - "address": "ar2dDEehonEYXkJkXyZGNxAZhU8vFKmrtPKgebmKDpMvYz8YPjiRztfR5WMWpH8u6MCqsVpqnJ5bh5VVgP2Sw1Xh2iWsqC4ro", - "percentage": 1 - } - ], - "blockRefreshInterval": 500, - "clientConnectionTimeout": 600, - "banning": - { - "enabled": true, - "time": 600, - "invalidPercent": 50, - "checkThreshold": 50 - }, - "ports": - { - "6360": - { - "listenAddress": "0.0.0.0", - "difficulty": 50000, - "name": "CPU Mining", - "varDiff": - { - "minDiff": 15000, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30 - } - } - }, - "daemons": - [ - { - "host": "127.0.0.1", - "port": 19994, - "user": "user", - "password": "password" - }, - { - "host": "127.0.0.1", - "port": 19995, - "user": "user", - "password": "password", - "category": "wallet" - } - ], - "paymentProcessing": - { - "enabled": true, - "minimumPayment": 0.25, - "minimumPaymentToPaymentId": 1.0, - "transferSplit": true, - "payoutScheme": "PPLNS", - "payoutSchemeConfig": - { - "factor": 0.5 - } - } - } - ] -} diff --git a/examples/cortex_pool.json b/examples/cortex_pool.json new file mode 100644 index 0000000000..0b5e48bb11 --- /dev/null +++ b/examples/cortex_pool.json @@ -0,0 +1,125 @@ +{ + "logging": { + "level": "info", + "enableConsoleLog": true, + "enableConsoleColors": true, + "logFile": "", + "apiLogFile": "", + "logBaseDirectory": "", + "perPoolLogFile": false + }, + "banning": { + "manager": "Integrated", + "banOnJunkReceive": false, + "banOnInvalidShares": false + }, + "notifications": { + "enabled": false, + "email": { + "host": "smtp.example.com", + "port": 587, + "user": "user", + "password": "password", + "fromAddress": "info@yourpool.org", + "fromName": "pool support" + }, + "admin": { + "enabled": false, + "emailAddress": "user@example.com", + "notifyBlockFound": true + } + }, + "persistence": { + "postgres": { + "host": "127.0.0.1", + "port": 5432, + "user": "miningcore", + "password": "password", + "database": "miningcore" + } + }, + "paymentProcessing": { + "enabled": true, + "interval": 100, + "shareRecoveryFile": "recovered-shares.txt" + }, + "api": { + "enabled": true, + "listenAddress": "*", + "port": 4000, + "metricsIpWhitelist": [], + "rateLimiting": { + "disabled": true, + "rules": [ + { + "Endpoint": "*", + "Period": "1s", + "Limit": 5 + } + ], + "ipWhitelist": [ + "" + ] + } + }, + "clusterName": "eu1", + "pools": [ + { + "id": "ctxc1", + "enabled": true, + "coin": "cortex", + "address": "0x6dd47dff7cf7daae47331f7f3556c0a31ab2511b", + "rewardRecipients": [ + { + "type": "op", + "address": "0x6dd47dff7cf7daae47331f7f3556c0a31ab2511b", + "percentage": 1.0 + } + ], + "blockRefreshInterval": 120, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "4073": { + "name": "GPU-SMALL", + "listenAddress": "*", + "difficulty": 0.0000000008128, + "varDiff": { + "minDiff": 0.0000000008128, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30 + } + } + }, + "chainTypeOverride": "Cortex", + "daemons": [ + { + "host": "127.0.0.1", + "port": 8545, + "user": "", + "password": "" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + }, + "gas": 21000, + "maxFeePerGas": 50000000000, + "BlockSearchOffset": 100, + "keepUncles": false, + "keepTransactionFees": false + } + } + ] +} \ No newline at end of file diff --git a/examples/handshake_pool.json b/examples/handshake_pool.json index d12d163a85..5d7e9d4120 100644 --- a/examples/handshake_pool.json +++ b/examples/handshake_pool.json @@ -75,6 +75,7 @@ "percentage": 1 } ], + "enableAsicBoost": true, "blockRefreshInterval": 250, "jobRebroadcastTimeout": 0, "clientConnectionTimeout": 600, diff --git a/examples/kaspa_pool.json b/examples/kaspa_pool.json index aa9ff89253..f53f361f18 100644 --- a/examples/kaspa_pool.json +++ b/examples/kaspa_pool.json @@ -75,6 +75,7 @@ } ], "protobufWalletRpcServiceName": "kaspawalletd.kaspawalletd", + "enableAsicBoost": true, "clientConnectionTimeout": 600, "banning": { "enabled": true, @@ -130,6 +131,8 @@ "enabled": true, "walletPassword": "", "minimumPayment": 1, + "versionEnablingMaxFee": "v0.12.18-rc5", + "maxFee": 200000, "payoutScheme": "PPLNS", "payoutSchemeConfig": { "factor": 0.5 diff --git a/examples/veruscoin_pool.json b/examples/veruscoin_pool.json index 295a2e1423..5ca7534e1e 100644 --- a/examples/veruscoin_pool.json +++ b/examples/veruscoin_pool.json @@ -96,10 +96,10 @@ "ports": { "3092": { "listenAddress": "0.0.0.0", - "difficulty": 256, + "difficulty": 25600000, "varDiff": { - "minDiff": 256, - "maxDiff": 1048576000, + "minDiff": 25600000, + "maxDiff": null, "targetTime": 15, "retargetTime": 90, "variancePercent": 30, @@ -108,13 +108,13 @@ }, "3093": { "listenAddress": "0.0.0.0", - "difficulty": 256, + "difficulty": 25600000, "tls": true, "tlsPfxFile": "", "tlsPfxPassword": "password", "varDiff": { - "minDiff": 256, - "maxDiff": 1048576000, + "minDiff": 25600000, + "maxDiff": null, "targetTime": 15, "retargetTime": 90, "variancePercent": 30, diff --git a/examples/warthog_pool.json b/examples/warthog_pool.json new file mode 100644 index 0000000000..ebe22690f4 --- /dev/null +++ b/examples/warthog_pool.json @@ -0,0 +1,119 @@ +{ + "logging": { + "level": "info", + "enableConsoleLog": true, + "enableConsoleColors": true, + "logFile": "", + "apiLogFile": "", + "logBaseDirectory": "", + "perPoolLogFile": false + }, + "banning": { + "manager": "Integrated", + "banOnJunkReceive": false, + "banOnInvalidShares": false + }, + "notifications": { + "enabled": false, + "email": { + "host": "smtp.example.com", + "port": 587, + "user": "user", + "password": "password", + "fromAddress": "info@yourpool.org", + "fromName": "support" + }, + "admin": { + "enabled": false, + "emailAddress": "user@example.com", + "notifyBlockFound": true + } + }, + "persistence": { + "postgres": { + "host": "127.0.0.1", + "port": 5432, + "user": "miningcore", + "password": "password", + "database": "miningcore" + } + }, + "paymentProcessing": { + "enabled": true, + "interval": 600, + "shareRecoveryFile": "recovered-shares.txt" + }, + "api": { + "enabled": true, + "listenAddress": "*", + "port": 4000, + "metricsIpWhitelist": [], + "rateLimiting": { + "disabled": true, + "rules": [ + { + "Endpoint": "*", + "Period": "1s", + "Limit": 5 + } + ], + "ipWhitelist": [ + "" + ] + } + }, + "pools": [{ + "id": "wart1", + "enabled": true, + "coin": "warthog", + "address": "5d896758ee0ade5f09fa93d012783beddd82a6ff322f2073", + "rewardRecipients": [ + { + "type": "op", + "address": "5d896758ee0ade5f09fa93d012783beddd82a6ff322f2073", + "percentage": 1.0 + } + ], + "blockRefreshInterval": 250, + "jobRebroadcastTimeout": 0, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "4073": { + "name": "GPU-SMALL", + "listenAddress": "*", + "difficulty": 512000000, + "varDiff": { + "minDiff": 256000000, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 100, + "maxDelta": 512 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 3000, + "user": "", + "password": "" + } + ], + "paymentProcessing": { + "walletPrivateKey": "", + "enabled": true, + "minimumPayment": 1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }] +} \ No newline at end of file diff --git a/examples/xelis_pool.json b/examples/xelis_pool.json new file mode 100644 index 0000000000..85cb26b0e1 --- /dev/null +++ b/examples/xelis_pool.json @@ -0,0 +1,125 @@ +{ + "logging": { + "level": "info", + "enableConsoleLog": true, + "enableConsoleColors": true, + "logFile": "", + "apiLogFile": "", + "logBaseDirectory": "", + "perPoolLogFile": false + }, + "banning": { + "manager": "Integrated", + "banOnJunkReceive": false, + "banOnInvalidShares": false + }, + "notifications": { + "enabled": false, + "email": { + "host": "smtp.example.com", + "port": 587, + "user": "user", + "password": "password", + "fromAddress": "info@yourpool.org", + "fromName": "support" + }, + "admin": { + "enabled": false, + "emailAddress": "user@example.com", + "notifyBlockFound": true + } + }, + "persistence": { + "postgres": { + "host": "127.0.0.1", + "port": 5432, + "user": "miningcore", + "password": "password", + "database": "miningcore" + } + }, + "paymentProcessing": { + "enabled": true, + "interval": 600, + "shareRecoveryFile": "recovered-shares.txt" + }, + "api": { + "enabled": true, + "listenAddress": "*", + "port": 4000, + "metricsIpWhitelist": [], + "rateLimiting": { + "disabled": true, + "rules": [ + { + "Endpoint": "*", + "Period": "1s", + "Limit": 5 + } + ], + "ipWhitelist": [ + "" + ] + } + }, + "pools": [{ + "id": "xel1", + "enabled": true, + "coin": "xelis", + "address": "xel:ajnsfv065qusndt0hfsngecrnf5690drmqmc0uq0etlx8zjlcyzqq2slgvt", + "rewardRecipients": [ + { + "type": "op", + "address": "xel:ajnsfv065qusndt0hfsngecrnf5690drmqmc0uq0etlx8zjlcyzqq2slgvt", + "percentage": 1.0 + } + ], + "blockRefreshInterval": 250, + "jobRebroadcastTimeout": 0, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "4073": { + "name": "GPU-SMALL", + "listenAddress": "*", + "difficulty": 1024000, + "varDiff": { + "minDiff": 512000, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 100, + "maxDelta": 512 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 8080, + "user": null, + "password": null + }, + { + "host": "127.0.0.1", + "port": 8081, + "user": "", + "password": "", + "category": "wallet" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }] +} \ No newline at end of file diff --git a/examples/zano_pool.json b/examples/zano_pool.json new file mode 100644 index 0000000000..954266a3af --- /dev/null +++ b/examples/zano_pool.json @@ -0,0 +1,141 @@ +{ + "logging": { + "level": "info", + "enableConsoleLog": true, + "enableConsoleColors": true, + "logFile": "", + "apiLogFile": "", + "logBaseDirectory": "", + "perPoolLogFile": false + }, + "banning": { + "manager": "Integrated", + "banOnJunkReceive": true, + "banOnInvalidShares": false + }, + "notifications": { + "enabled": false, + "email": { + "host": "smtp.example.com", + "port": 587, + "user": "user", + "password": "password", + "fromAddress": "info@yourpool.org", + "fromName": "pool support" + }, + "admin": { + "enabled": false, + "emailAddress": "user@example.com", + "notifyBlockFound": true + } + }, + "persistence": { + "postgres": { + "host": "127.0.0.1", + "port": 5432, + "user": "miningcore", + "password": "password", + "database": "miningcore" + } + }, + "paymentProcessing": { + "enabled": true, + "interval": 600, + "shareRecoveryFile": "recovered-shares.txt" + }, + "api": { + "enabled": true, + "listenAddress": "*", + "port": 4000, + "metricsIpWhitelist": [], + "rateLimiting": { + "disabled": true, + "rules": [ + { + "Endpoint": "*", + "Period": "1s", + "Limit": 5 + } + ], + "ipWhitelist": [ + "" + ] + } + }, + "pools": [ + { + "id": "zano1", + "enabled": true, + "coin": "zano", + "address": "ZxDKT1aqiEXPA5cDADtYEfMR1oXsRd68bby4nzUvVmnjHzzrfvjwhNdQ9yiWNeGutzg9LZdwsbP2FGB1gNpZXiYY1fCfpw33c", + "rewardRecipients": [ + { + "type": "op", + "address": "ZxDKT1aqiEXPA5cDADtYEfMR1oXsRd68bby4nzUvVmnjHzzrfvjwhNdQ9yiWNeGutzg9LZdwsbP2FGB1gNpZXiYY1fCfpw33c", + "percentage": 0.1 + } + ], + "blockRefreshInterval": 250, + "jobRebroadcastTimeout": 3, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3364": { + "listenAddress": "0.0.0.0", + "difficulty": 250000000, + "varDiff": { + "minDiff": 250000000, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "3365": { + "listenAddress": "0.0.0.0", + "difficulty": 250000000, + "tls": true, + "tlsPfxFile": "", + "tlsPfxPassword": "password", + "varDiff": { + "minDiff": 250000000, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 11211, + "user": null, + "password": null + }, + { + "host": "127.0.0.1", + "port": 11212, + "user": null, + "password": null, + "category": "wallet" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 0.1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + } + ] +} \ No newline at end of file diff --git a/src/Miningcore.Tests/Miningcore.Tests.csproj b/src/Miningcore.Tests/Miningcore.Tests.csproj index 7ea90a8840..f552aeab8d 100644 --- a/src/Miningcore.Tests/Miningcore.Tests.csproj +++ b/src/Miningcore.Tests/Miningcore.Tests.csproj @@ -37,8 +37,8 @@ - - + + diff --git a/src/Miningcore/Api/Controllers/AdminApiController.cs b/src/Miningcore/Api/Controllers/AdminApiController.cs index aa54e54d79..24fc289b1e 100644 --- a/src/Miningcore/Api/Controllers/AdminApiController.cs +++ b/src/Miningcore/Api/Controllers/AdminApiController.cs @@ -127,7 +127,7 @@ public ActionResult EnablePoolPaymentProcessing(string poolId) poolInstance.Config.PaymentProcessing.Enabled = true; logger.Info(()=> $"Enabled payment processing for pool {poolId}"); - return "Payment Enabled Successfully"; + return "Ok"; } [HttpGet("payment/processing/{poolId}/disable")] @@ -142,40 +142,8 @@ public ActionResult DisablePoolPaymentProcessing(string poolId) poolInstance.Config.PaymentProcessing.Enabled = false; logger.Info(()=> $"Disabled payment processing for pool {poolId}"); - return "Payment Disable Successfully"; - } - - // testing pool id enable / disable on admin api start here - [HttpGet("{poolId}/enable")] - public ActionResult EnablePoolId(string poolId) - { - if (string.IsNullOrEmpty(poolId)) - throw new ApiException("Missing pool ID", HttpStatusCode.BadRequest); - - pools.TryGetValue(poolId, out var poolInstance); - if(poolInstance == null) - return "-1"; - - poolInstance.Config.Enabled = true; - logger.Info(()=> $"Enabled pool ID{poolId}"); - return "{poolId} Enabled Successfully"; - } - - [HttpGet("{poolId}/disable")] - public ActionResult DisablePoolId(string poolId) - { - if (string.IsNullOrEmpty(poolId)) - throw new ApiException("Missing pool ID", HttpStatusCode.BadRequest); - - pools.TryGetValue(poolId, out var poolInstance); - if(poolInstance == null) - return "-1"; - - poolInstance.Config.Enabled = false; - logger.Info(()=> $"Disabled pool Id{poolId}"); - return "{poolId} Disabled Successfully"; + return "Ok"; } - // testing pool id enable / disable on admin api end here [HttpGet("stats/gc")] public ActionResult GetGcStats() diff --git a/src/Miningcore/Api/Controllers/PoolApiController.cs b/src/Miningcore/Api/Controllers/PoolApiController.cs index d491e9ec4f..bdaa34e8cc 100644 --- a/src/Miningcore/Api/Controllers/PoolApiController.cs +++ b/src/Miningcore/Api/Controllers/PoolApiController.cs @@ -50,61 +50,86 @@ public PoolApiController(IComponentContext ctx, IActionDescriptorCollectionProvi #region Actions [HttpGet] - public async Task Get(CancellationToken ct, [FromQuery] uint topMinersRange = 24) + public async Task Get(CancellationToken ct, + [FromServices] CoinMarketCap.CoinMarketCapService service, + [FromQuery] uint topMinersRange = 24) { - var response = new GetPoolsResponse + try { - Pools = await Task.WhenAll(clusterConfig.Pools.Where(x => x.Enabled).Select(async config => + var response = new GetPoolsResponse { - // load stats - var stats = await cf.Run(con => statsRepo.GetLastPoolStatsAsync(con, config.Id, ct)); + Pools = await Task.WhenAll(clusterConfig.Pools.Where(x => x.Enabled).Select(async config => + { + // load stats + var stats = await cf.Run(con => statsRepo.GetLastPoolStatsAsync(con, config.Id, ct)); + + // get pool + pools.TryGetValue(config.Id, out var pool); + + // map + var result = config.ToPoolInfo(mapper, stats, pool); + + // enrich + result.TotalPaid = await cf.Run(con => statsRepo.GetTotalPoolPaymentsAsync(con, config.Id, ct)); + result.TotalBlocks = await cf.Run(con => blocksRepo.GetPoolBlockCountAsync(con, config.Id, ct)); + result.TotalConfirmedBlocks = await cf.Run(con => blocksRepo.GetTotalConfirmedBlocksAsync(con, config.Id, ct)); + result.TotalPendingBlocks = await cf.Run(con => blocksRepo.GetTotalPendingBlocksAsync(con, config.Id, ct)); + // get reward of the last confirmed block and set BlockReward + result.BlockReward = await cf.Run(con => blocksRepo.GetLastConfirmedBlockRewardAsync(con, config.Id, ct)); + var lastBlockTime = await cf.Run(con => blocksRepo.GetLastPoolBlockTimeAsync(con, config.Id, ct)); + result.LastPoolBlockTime = lastBlockTime; + + if(lastBlockTime.HasValue) + { + var startTime = lastBlockTime.Value; + var poolEffort = await cf.Run(con => shareRepo.GetEffortBetweenCreatedAsync(con, config.Id, pool.ShareMultiplier, startTime, clock.Now, ct)); + if(poolEffort.HasValue) + result.PoolEffort = poolEffort.Value; + } - // get pool - pools.TryGetValue(config.Id, out var pool); + var from = clock.Now.AddHours(-topMinersRange); - // map - var result = config.ToPoolInfo(mapper, stats, pool); + var minersByHashrate = await cf.Run(con => statsRepo.PagePoolMinersByHashrateAsync(con, config.Id, from, 0, 15, ct)); - // enrich - result.TotalPaid = await cf.Run(con => statsRepo.GetTotalPoolPaymentsAsync(con, config.Id, ct)); - result.TotalBlocks = await cf.Run(con => blocksRepo.GetPoolBlockCountAsync(con, config.Id, ct)); - var lastBlockTime = await cf.Run(con => blocksRepo.GetLastPoolBlockTimeAsync(con, config.Id)); - result.LastPoolBlockTime = lastBlockTime; + result.TopMiners = minersByHashrate.Select(mapper.Map).ToArray(); - var payoutConfig = config.PaymentProcessing; - result.PaymentProcessing.PayoutSchemeConfig = payoutConfig?.PayoutSchemeConfig.ToObject(); - // display block finder percentage only if PPLNSBF is activated - if(payoutConfig?.PayoutScheme != PayoutScheme.PPLNSBF) - result.PaymentProcessing.PayoutSchemeConfig.BlockFinderPercentage = null; + return result; + }).ToArray()) + }; - if(lastBlockTime.HasValue) + if(clusterConfig.CoinMarketCapApi.Enabled) + { + var symbols = string.Join(",", response?.Pools?.Select(Q => Q.Coin.Symbol)); + if(!string.IsNullOrWhiteSpace(symbols)) { - var startTime = lastBlockTime.Value; - var poolEffort = await cf.Run(con => shareRepo.GetEffortBetweenCreatedAsync(con, config.Id, startTime, clock.Now)); - - //kaspa effort fix start here - // If the effort is less than 1e-8, multiply it by 4e9 - if(poolEffort.HasValue && poolEffort.Value < 1e-8) + var result = await service.GetCryptoQuoteAsync(symbols); + foreach(var item in response.Pools) { - poolEffort *= 4e9; + if(result.Data.TryGetValue(item.Coin.Symbol, out var marketCapData)) + { + var marketData = marketCapData.Where(Q => string.Equals(item.Coin.Symbol, Q.Symbol, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); + if(marketData?.Quote != null && marketData.Quote.TryGetValue("USD", out var quote) && quote?.Price != null && quote.Price.HasValue) + { + item.Coin.Price = Math.Round(quote.Price.Value, 4); + item.Coin.Logo = marketData.Logo; + item.Coin.VolumeChange24H = quote.VolumeChange24H.HasValue ? Math.Round(quote.VolumeChange24H.Value, 4) : "n/a"; + } + else + { + item.Coin.Price = "n/a"; + item.Coin.Logo = "n/a"; + item.Coin.VolumeChange24H = "n/a"; + } + } } - //kaspa effort fix end here - - if(poolEffort.HasValue) - result.PoolEffort = poolEffort.Value; } - - var from = clock.Now.AddHours(-topMinersRange); - - var minersByHashrate = await cf.Run(con => statsRepo.PagePoolMinersByHashrateAsync(con, config.Id, from, 0, 15, ct)); - - result.TopMiners = minersByHashrate.Select(mapper.Map).ToArray(); - - return result; - }).ToArray()) - }; - - return response; + } + return Ok(response); + } + catch(Exception ex) + { + return Problem(detail: ex.Message, statusCode: 500, title: "Internal Server Error"); + } } [HttpGet("/api/help")] @@ -152,28 +177,17 @@ public async Task GetPoolInfoAsync(string poolId, CancellationT // enrich response.Pool.TotalPaid = await cf.Run(con => statsRepo.GetTotalPoolPaymentsAsync(con, pool.Id, ct)); response.Pool.TotalBlocks = await cf.Run(con => blocksRepo.GetPoolBlockCountAsync(con, pool.Id, ct)); - var lastBlockTime = await cf.Run(con => blocksRepo.GetLastPoolBlockTimeAsync(con, pool.Id)); + response.Pool.TotalConfirmedBlocks = await cf.Run(con => blocksRepo.GetTotalConfirmedBlocksAsync(con, pool.Id, ct)); + response.Pool.TotalPendingBlocks = await cf.Run(con => blocksRepo.GetTotalPendingBlocksAsync(con, pool.Id, ct)); + // get reward of the last confirmed block and set BlockReward + response.Pool.BlockReward = await cf.Run(con => blocksRepo.GetLastConfirmedBlockRewardAsync(con, pool.Id, ct)); + var lastBlockTime = await cf.Run(con => blocksRepo.GetLastPoolBlockTimeAsync(con, pool.Id, ct)); response.Pool.LastPoolBlockTime = lastBlockTime; - var payoutConfig = pool.PaymentProcessing; - response.Pool.PaymentProcessing.PayoutSchemeConfig = payoutConfig?.PayoutSchemeConfig.ToObject(); - // display block finder percentage only if PPLNSBF is activated - if(payoutConfig?.PayoutScheme != PayoutScheme.PPLNSBF) - response.Pool.PaymentProcessing.PayoutSchemeConfig.BlockFinderPercentage = null; - if(lastBlockTime.HasValue) { var startTime = lastBlockTime.Value; - var poolEffort = await cf.Run(con => shareRepo.GetEffortBetweenCreatedAsync(con, pool.Id, startTime, clock.Now)); - - //kaspa effort fix start here - // If the effort is less than 1e-8, multiply it by 4e9 - if(poolEffort.HasValue && poolEffort.Value < 1e-8) - { - poolEffort *= 4e9; - } - //kaspa effort fix end here - + var poolEffort = await cf.Run(con => shareRepo.GetEffortBetweenCreatedAsync(con, pool.Id, poolInstance.ShareMultiplier, startTime, clock.Now, ct)); if(poolEffort.HasValue) response.Pool.PoolEffort = poolEffort.Value; } @@ -274,20 +288,6 @@ public async Task PagePoolMinersAsync( block.InfoLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHashPH, block.Hash); } } - - //kaspa effort fix start here - // If the effort is less than 1e-8, multiply it by 4e9 - if(block.Effort < 1e-8) - { - block.Effort *= 4e9; - } - - // If the minerEffort is less than 1e-8, multiply it by 4e9 - if(block.MinerEffort < 1e-8) - { - block.MinerEffort *= 4e9; - } - //kaspa effort fix end here } return blocks; @@ -303,7 +303,7 @@ public async Task PagePoolMinersAsync( var blockStates = state is { Length: > 0 } ? state : new[] { BlockStatus.Confirmed, BlockStatus.Pending, BlockStatus.Orphaned }; - + uint itemCount = await cf.Run(con => blocksRepo.GetPoolBlockCountAsync(con, poolId, ct)); uint pageCount = (uint) Math.Floor(itemCount / (double) pageSize); @@ -437,25 +437,22 @@ public async Task PagePoolMinersAsync( stats.LastPaymentLink = string.Format(baseUrl, statsResult.LastPayment.TransactionConfirmationData); } - var lastBlockTime = await cf.Run(con => blocksRepo.GetLastMinerBlockTimeAsync(con, pool.Id, address)); + var lastBlockTime = await cf.Run(con => blocksRepo.GetLastPoolBlockTimeAsync(con, pool.Id, ct)); if(lastBlockTime.HasValue) - { - var startTime = lastBlockTime.Value; - var minerEffort = await cf.Run(con => shareRepo.GetMinerEffortBetweenCreatedAsync(con, pool.Id, address, startTime, clock.Now)); - - //kaspa effort fix start here - // If the effort is less than 1e-8, multiply it by 4e9 - if(minerEffort.HasValue && minerEffort.Value < 1e-8) - { - minerEffort *= 4e9; - } - //kaspa effort fix end here - - if(minerEffort.HasValue) - stats.MinerEffort = minerEffort.Value; - } + { + var startTime = lastBlockTime.Value; + var minerEffort = await cf.Run(con => shareRepo.GetMinerEffortBetweenCreatedAsync(con, pool.Id, address, startTime, clock.Now, ct)); + if(minerEffort.HasValue) + stats.MinerEffort = minerEffort.Value; + } stats.PerformanceSamples = await GetMinerPerformanceInternal(perfMode, pool, address, ct); + + // add total confirmed and pending blocks + var totalConfirmedBlocks = await cf.Run(con => statsRepo.GetMinerTotalConfirmedBlocksAsync(con, pool.Id, address, ct)); + var totalPendingBlocks = await cf.Run(con => statsRepo.GetMinerTotalPendingBlocksAsync(con, pool.Id, address, ct)); + stats.TotalConfirmedBlocks = totalConfirmedBlocks; + stats.TotalPendingBlocks = totalPendingBlocks; } return stats; @@ -511,7 +508,7 @@ public async Task PagePoolMinersAsync( { var pool = GetPool(poolId); var ct = HttpContext.RequestAborted; - + if(string.IsNullOrEmpty(address)) throw new ApiException("Invalid or missing miner address", HttpStatusCode.NotFound); @@ -521,7 +518,7 @@ public async Task PagePoolMinersAsync( var blockStates = state is { Length: > 0 } ? state : new[] { BlockStatus.Confirmed, BlockStatus.Pending, BlockStatus.Orphaned }; - + uint itemCount = await cf.Run(con => blocksRepo.GetMinerBlockCountAsync(con, poolId, address, ct)); uint pageCount = (uint) Math.Floor(itemCount / (double) pageSize); @@ -601,7 +598,7 @@ public async Task PagePoolMinersAsync( if(pool.Template.Family == CoinFamily.Ethereum) address = address.ToLower(); - + uint itemCount = await cf.Run(con => paymentsRepo.GetPaymentsCountAsync(con, poolId, address, ct)); uint pageCount = (uint) Math.Floor(itemCount / (double) pageSize); @@ -662,7 +659,7 @@ public async Task PagePoolMinersAsync( if(pool.Template.Family == CoinFamily.Ethereum) address = address.ToLower(); - + uint itemCount = await cf.Run(con => paymentsRepo.GetBalanceChangesCountAsync(con, poolId, address)); uint pageCount = (uint) Math.Floor(itemCount / (double) pageSize); diff --git a/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs b/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs index 301922bda0..c0ac2a86dd 100644 --- a/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs +++ b/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs @@ -6,6 +6,7 @@ using Miningcore.Blockchain.Ergo.Configuration; using Miningcore.Blockchain.Handshake.Configuration; using Miningcore.Blockchain.Kaspa.Configuration; +using Miningcore.Blockchain.Warthog.Configuration; using Miningcore.Configuration; using Miningcore.Extensions; using Miningcore.Mining; @@ -51,6 +52,9 @@ public static PoolInfo ToPoolInfo(this PoolConfig poolConfig, IMapper mapper, Pe case "kaspa": extra.StripValue(nameof(KaspaPaymentProcessingConfigExtra.WalletPassword)); break; + case "warthog": + extra.StripValue(nameof(WarthogPaymentProcessingConfigExtra.WalletPrivateKey)); + break; } } diff --git a/src/Miningcore/Api/Requests/GetCoinMarketCapRequest.cs b/src/Miningcore/Api/Requests/GetCoinMarketCapRequest.cs new file mode 100644 index 0000000000..825b6dc1fc --- /dev/null +++ b/src/Miningcore/Api/Requests/GetCoinMarketCapRequest.cs @@ -0,0 +1,438 @@ +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace Miningcore.Api.Requests +{ + public class CryptoApiResponse + { + [JsonPropertyName("status")] + [JsonProperty("status")] + public StatusInfo Status { get; set; } + + [JsonPropertyName("data")] + [JsonProperty("data")] + public Dictionary> Data { get; set; } + } + + public class StatusInfo + { + [JsonPropertyName("timestamp")] + [JsonProperty("timestamp")] + public DateTime? Timestamp { get; set; } + + [JsonPropertyName("error_code")] + [JsonProperty("error_code")] + public int ErrorCode { get; set; } + + [JsonPropertyName("error_message")] + [JsonProperty("error_message")] + public string ErrorMessage { get; set; } + + [JsonPropertyName("elapsed")] + [JsonProperty("elapsed")] + public int Elapsed { get; set; } + + [JsonPropertyName("credit_count")] + [JsonProperty("credit_count")] + public int CreditCount { get; set; } + + [JsonPropertyName("notice")] + [JsonProperty("notice")] + public string Notice { get; set; } + } + + public class CoinMarketCapData + { + [JsonPropertyName("id")] + [JsonProperty("id")] + public int Id { get; set; } + + [JsonPropertyName("name")] + [JsonProperty("name")] + public string Name { get; set; } + + [JsonPropertyName("symbol")] + [JsonProperty("symbol")] + public string Symbol { get; set; } + + [JsonPropertyName("logo")] + [JsonProperty("logo")] + public string Logo { get; set; } = "n/a"; + + [JsonPropertyName("slug")] + [JsonProperty("slug")] + public string Slug { get; set; } + + [JsonPropertyName("num_market_pairs")] + [JsonProperty("num_market_pairs")] + public int? NumMarketPairs { get; set; } + + [JsonPropertyName("date_added")] + [JsonProperty("date_added")] + public DateTime? DateAdded { get; set; } + + [JsonPropertyName("tags")] + [JsonProperty("tags")] + public List Tags { get; set; } + + [JsonPropertyName("max_supply")] + [JsonProperty("max_supply")] + public long? MaxSupply { get; set; } + + [JsonPropertyName("circulating_supply")] + [JsonProperty("circulating_supply")] + public double CirculatingSupply { get; set; } + + [JsonPropertyName("total_supply")] + [JsonProperty("total_supply")] + public double TotalSupply { get; set; } + + [JsonPropertyName("is_active")] + [JsonProperty("is_active")] + public int IsActive { get; set; } + + [JsonPropertyName("infinite_supply")] + [JsonProperty("infinite_supply")] + public bool InfiniteSupply { get; set; } + + [JsonPropertyName("platform")] + [JsonProperty("platform")] + public Platform Platform { get; set; } + + [JsonPropertyName("cmc_rank")] + [JsonProperty("cmc_rank")] + public int? CmcRank { get; set; } + + [JsonPropertyName("is_fiat")] + [JsonProperty("is_fiat")] + public int IsFiat { get; set; } + + [JsonPropertyName("self_reported_circulating_supply")] + [JsonProperty("self_reported_circulating_supply")] + public double? SelfReportedCirculatingSupply { get; set; } + + [JsonPropertyName("self_reported_market_cap")] + [JsonProperty("self_reported_market_cap")] + public double? SelfReportedMarketCap { get; set; } + + [JsonPropertyName("tvl_ratio")] + [JsonProperty("tvl_ratio")] + public double? TvlRatio { get; set; } + + [JsonPropertyName("last_updated")] + [JsonProperty("last_updated")] + public DateTime? LastUpdated { get; set; } + + [JsonPropertyName("quote")] + [JsonProperty("quote")] + public Dictionary Quote { get; set; } + } + + public class Tag + { + [JsonPropertyName("slug")] + [JsonProperty("slug")] + public string Slug { get; set; } + + [JsonPropertyName("name")] + [JsonProperty("name")] + public string Name { get; set; } + + [JsonPropertyName("category")] + [JsonProperty("category")] + public string Category { get; set; } + } + + public class Platform + { + [JsonPropertyName("id")] + [JsonProperty("id")] + public int Id { get; set; } + + [JsonPropertyName("name")] + [JsonProperty("name")] + public string Name { get; set; } + + [JsonPropertyName("symbol")] + [JsonProperty("symbol")] + public string Symbol { get; set; } + + [JsonPropertyName("slug")] + [JsonProperty("slug")] + public string Slug { get; set; } + + [JsonPropertyName("token_address")] + [JsonProperty("token_address")] + public string TokenAddress { get; set; } + } + + public class Quote + { + [JsonPropertyName("price")] + [JsonProperty("price")] + public double? Price { get; set; } + + [JsonPropertyName("volume_24h")] + [JsonProperty("volume_24h")] + public double? Volume24H { get; set; } + + [JsonPropertyName("volume_change_24h")] + [JsonProperty("volume_change_24h")] + public double? VolumeChange24H { get; set; } + + [JsonPropertyName("percent_change_1h")] + [JsonProperty("percent_change_1h")] + public double? PercentChange1H { get; set; } + + [JsonPropertyName("percent_change_24h")] + [JsonProperty("percent_change_24h")] + public double? PercentChange24H { get; set; } + + [JsonPropertyName("percent_change_7d")] + [JsonProperty("percent_change_7d")] + public double? PercentChange7D { get; set; } + + [JsonPropertyName("percent_change_30d")] + [JsonProperty("percent_change_30d")] + public double? PercentChange30D { get; set; } + + [JsonPropertyName("percent_change_60d")] + [JsonProperty("percent_change_60d")] + public double? PercentChange60D { get; set; } + + [JsonPropertyName("percent_change_90d")] + [JsonProperty("percent_change_90d")] + public double? PercentChange90D { get; set; } + + [JsonPropertyName("market_cap")] + [JsonProperty("market_cap")] + public double? MarketCap { get; set; } + + [JsonPropertyName("market_cap_dominance")] + [JsonProperty("market_cap_dominance")] + public double? MarketCapDominance { get; set; } + + [JsonPropertyName("fully_diluted_market_cap")] + [JsonProperty("fully_diluted_market_cap")] + public double? FullyDilutedMarketCap { get; set; } + + [JsonPropertyName("tvl")] + [JsonProperty("tvl")] + public double? Tvl { get; set; } + + [JsonPropertyName("last_updated")] + [JsonProperty("last_updated")] + public DateTime? LastUpdated { get; set; } + } + + + public class InfoApiResponse + { + [JsonPropertyName("status")] + [JsonProperty("status")] + public InfoStatus Status { get; set; } + + [JsonPropertyName("data")] + [JsonProperty("data")] + public Dictionary Data { get; set; } + } + + public class InfoStatus + { + [JsonPropertyName("timestamp")] + [JsonProperty("timestamp")] + public DateTime? Timestamp { get; set; } + + [JsonPropertyName("error_code")] + [JsonProperty("error_code")] + public int ErrorCode { get; set; } + + [JsonPropertyName("error_message")] + [JsonProperty("error_message")] + public string ErrorMessage { get; set; } + + [JsonPropertyName("elapsed")] + [JsonProperty("elapsed")] + public int Elapsed { get; set; } + + [JsonPropertyName("credit_count")] + [JsonProperty("credit_count")] + public int CreditCount { get; set; } + + [JsonPropertyName("notice")] + [JsonProperty("notice")] + public string Notice { get; set; } + } + + public class InfoCryptoData + { + [JsonPropertyName("id")] + [JsonProperty("id")] + public int Id { get; set; } + + [JsonPropertyName("name")] + [JsonProperty("name")] + public string Name { get; set; } + + [JsonPropertyName("symbol")] + [JsonProperty("symbol")] + public string Symbol { get; set; } + + [JsonPropertyName("category")] + [JsonProperty("category")] + public string Category { get; set; } + + [JsonPropertyName("description")] + [JsonProperty("description")] + public string Description { get; set; } + + [JsonPropertyName("slug")] + [JsonProperty("slug")] + public string Slug { get; set; } + + [JsonPropertyName("logo")] + [JsonProperty("logo")] + public string Logo { get; set; } + + [JsonPropertyName("subreddit")] + [JsonProperty("subreddit")] + public string Subreddit { get; set; } + + [JsonPropertyName("notice")] + [JsonProperty("notice")] + public string Notice { get; set; } + + [JsonPropertyName("tags")] + [JsonProperty("tags")] + public List Tags { get; set; } + + [JsonPropertyName("tag-names")] + [JsonProperty("tag-names")] + public List TagNames { get; set; } + + [JsonPropertyName("tag-groups")] + [JsonProperty("tag-groups")] + public List TagGroups { get; set; } + + [JsonPropertyName("urls")] + [JsonProperty("urls")] + public InfoUrls Urls { get; set; } + + [JsonPropertyName("platform")] + [JsonProperty("platform")] + public InfoPlatform Platform { get; set; } + + [JsonPropertyName("date_added")] + [JsonProperty("date_added")] + public DateTime? DateAdded { get; set; } + + [JsonPropertyName("twitter_username")] + [JsonProperty("twitter_username")] + public string TwitterUsername { get; set; } + + [JsonPropertyName("is_hidden")] + [JsonProperty("is_hidden")] + public int IsHidden { get; set; } + + [JsonPropertyName("date_launched")] + [JsonProperty("date_launched")] + public DateTime? DateLaunched { get; set; } + + [JsonPropertyName("contract_address")] + [JsonProperty("contract_address")] + public List ContractAddress { get; set; } + + [JsonPropertyName("self_reported_circulating_supply")] + [JsonProperty("self_reported_circulating_supply")] + public decimal? SelfReportedCirculatingSupply { get; set; } + + [JsonPropertyName("self_reported_tags")] + [JsonProperty("self_reported_tags")] + public List SelfReportedTags { get; set; } + + [JsonPropertyName("self_reported_market_cap")] + [JsonProperty("self_reported_market_cap")] + public decimal? SelfReportedMarketCap { get; set; } + + [JsonPropertyName("infinite_supply")] + [JsonProperty("infinite_supply")] + public bool InfiniteSupply { get; set; } + } + + public class InfoUrls + { + [JsonPropertyName("website")] + [JsonProperty("website")] + public List Website { get; set; } + + [JsonPropertyName("twitter")] + [JsonProperty("twitter")] + public List Twitter { get; set; } + + [JsonPropertyName("message_board")] + [JsonProperty("message_board")] + public List MessageBoard { get; set; } + + [JsonPropertyName("chat")] + [JsonProperty("chat")] + public List Chat { get; set; } + + [JsonPropertyName("facebook")] + [JsonProperty("facebook")] + public List Facebook { get; set; } + + [JsonPropertyName("explorer")] + [JsonProperty("explorer")] + public List Explorer { get; set; } + + [JsonPropertyName("reddit")] + [JsonProperty("reddit")] + public List Reddit { get; set; } + + [JsonPropertyName("technical_doc")] + [JsonProperty("technical_doc")] + public List TechnicalDoc { get; set; } + + [JsonPropertyName("source_code")] + [JsonProperty("source_code")] + public List SourceCode { get; set; } + + [JsonPropertyName("announcement")] + [JsonProperty("announcement")] + public List Announcement { get; set; } + } + + public class InfoPlatform + { + [JsonPropertyName("id")] + [JsonProperty("id")] + public string Id { get; set; } + + [JsonPropertyName("name")] + [JsonProperty("name")] + public string Name { get; set; } + + [JsonPropertyName("slug")] + [JsonProperty("slug")] + public string Slug { get; set; } + + [JsonPropertyName("symbol")] + [JsonProperty("symbol")] + public string Symbol { get; set; } + + [JsonPropertyName("token_address")] + [JsonProperty("token_address")] + public string TokenAddress { get; set; } + } + + public class InfoContractAddress + { + [JsonPropertyName("contract_address")] + [JsonProperty("contract_address")] + public string Address { get; set; } + + [JsonPropertyName("platform")] + [JsonProperty("platform")] + public InfoPlatform Platform { get; set; } + } +} diff --git a/src/Miningcore/Api/Responses/GetCoinMarketCapResponse.cs b/src/Miningcore/Api/Responses/GetCoinMarketCapResponse.cs new file mode 100644 index 0000000000..e27d1b39c4 --- /dev/null +++ b/src/Miningcore/Api/Responses/GetCoinMarketCapResponse.cs @@ -0,0 +1,7 @@ +namespace Miningcore.Api.Responses +{ + public class CoinMarketCapResponse + { + public double USDC { get; set; } + } +} diff --git a/src/Miningcore/Api/Responses/GetMinerStatsResponse.cs b/src/Miningcore/Api/Responses/GetMinerStatsResponse.cs index 7b16043abf..8c1672665a 100644 --- a/src/Miningcore/Api/Responses/GetMinerStatsResponse.cs +++ b/src/Miningcore/Api/Responses/GetMinerStatsResponse.cs @@ -30,4 +30,6 @@ public class MinerStats public string LastPaymentLink { get; set; } public WorkerPerformanceStatsContainer Performance { get; set; } public WorkerPerformanceStatsContainer[] PerformanceSamples { get; set; } + public long TotalConfirmedBlocks { get; set; } + public long TotalPendingBlocks { get; set; } } diff --git a/src/Miningcore/Api/Responses/GetPoolStatsResponse.cs b/src/Miningcore/Api/Responses/GetPoolStatsResponse.cs index 394a312ca5..65c5f0530f 100644 --- a/src/Miningcore/Api/Responses/GetPoolStatsResponse.cs +++ b/src/Miningcore/Api/Responses/GetPoolStatsResponse.cs @@ -2,9 +2,9 @@ namespace Miningcore.Api.Responses; public partial class AggregatedPoolStats { - public double PoolHashrate { get; set; } + public float PoolHashrate { get; set; } public int ConnectedMiners { get; set; } - public double ValidSharesPerSecond { get; set; } + public int ValidSharesPerSecond { get; set; } public double NetworkHashrate { get; set; } public double NetworkDifficulty { get; set; } diff --git a/src/Miningcore/Api/Responses/GetPoolsResponse.cs b/src/Miningcore/Api/Responses/GetPoolsResponse.cs index 624c5009ac..beac7d1046 100644 --- a/src/Miningcore/Api/Responses/GetPoolsResponse.cs +++ b/src/Miningcore/Api/Responses/GetPoolsResponse.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using Miningcore.Api.Requests; using Miningcore.Blockchain; using Miningcore.Configuration; using Miningcore.Mining; @@ -30,23 +31,22 @@ public class ApiCoinConfig [System.Text.Json.Serialization.JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string Discord { get; set; } - [System.Text.Json.Serialization.JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string Github{ get; set; } - [System.Text.Json.Serialization.JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string Telegram { get; set; } [System.Text.Json.Serialization.JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string CanonicalName { get; set; } -} -public class ApiPoolPayoutSchemeConfig -{ [System.Text.Json.Serialization.JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public decimal? Factor { get; set; } = 2.0m; + public object Price { get; set; } + + [System.Text.Json.Serialization.JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string Logo { get; set; } [System.Text.Json.Serialization.JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public decimal? BlockFinderPercentage { get; set; } = 5.0m; + [JsonPropertyName("volume_change_24h")] + [Newtonsoft.Json.JsonProperty("volume_change_24h")] + public object VolumeChange24H { get; set; } } public class ApiPoolPaymentProcessingConfig @@ -54,7 +54,7 @@ public class ApiPoolPaymentProcessingConfig public bool Enabled { get; set; } public decimal MinimumPayment { get; set; } // in pool-base-currency (ie. Bitcoin, not Satoshis) public string PayoutScheme { get; set; } - public ApiPoolPayoutSchemeConfig PayoutSchemeConfig { get; set; } + public JToken PayoutSchemeConfig { get; set; } [Newtonsoft.Json.JsonExtensionData] public IDictionary Extra { get; set; } @@ -83,6 +83,9 @@ public partial class PoolInfo public MinerPerformanceStats[] TopMiners { get; set; } public decimal TotalPaid { get; set; } public uint TotalBlocks { get; set; } + public uint TotalConfirmedBlocks { get; set; } + public uint TotalPendingBlocks { get; set; } + public decimal BlockReward { get; set; } public DateTime? LastPoolBlockTime { get; set; } public double PoolEffort { get; set; } } diff --git a/src/Miningcore/AutoMapperProfile.cs b/src/Miningcore/AutoMapperProfile.cs index 42c4d07e59..38f88b2b2e 100644 --- a/src/Miningcore/AutoMapperProfile.cs +++ b/src/Miningcore/AutoMapperProfile.cs @@ -47,7 +47,6 @@ public AutoMapperProfile() .ForMember(dest => dest.Market, opt => opt.MapFrom(src => src.Market)) .ForMember(dest => dest.Twitter, opt => opt.MapFrom(src => src.Twitter)) .ForMember(dest => dest.Discord, opt => opt.MapFrom(src => src.Discord)) - .ForMember(dest => dest.Github, opt => opt.MapFrom(src => src.Github)) .ForMember(dest => dest.Telegram, opt => opt.MapFrom(src => src.Telegram)) .ForMember(dest => dest.Algorithm, opt => opt.MapFrom(src => src.GetAlgorithmName())); @@ -64,7 +63,9 @@ public AutoMapperProfile() CreateMap() .ForMember(dest => dest.LastPayment, opt => opt.Ignore()) - .ForMember(dest => dest.LastPaymentLink, opt => opt.Ignore()); + .ForMember(dest => dest.LastPaymentLink, opt => opt.Ignore()) + .ForMember(dest => dest.TotalConfirmedBlocks, opt => opt.MapFrom(src => src.TotalConfirmedBlocks)) + .ForMember(dest => dest.TotalPendingBlocks, opt => opt.MapFrom(src => src.TotalPendingBlocks)); CreateMap(); CreateMap(); diff --git a/src/Miningcore/AutofacModule.cs b/src/Miningcore/AutofacModule.cs index d03faaf0c6..fb939c9497 100644 --- a/src/Miningcore/AutofacModule.cs +++ b/src/Miningcore/AutofacModule.cs @@ -14,6 +14,9 @@ using Miningcore.Blockchain.Kaspa; using Miningcore.Blockchain.Nexa; using Miningcore.Blockchain.Progpow; +using Miningcore.Blockchain.Warthog; +using Miningcore.Blockchain.Xelis; +using Miningcore.Blockchain.Zano; using Miningcore.Configuration; using Miningcore.Crypto; using Miningcore.Crypto.Hashing.Equihash; @@ -32,6 +35,7 @@ using Microsoft.IO; using Miningcore.Nicehash; using Miningcore.Pushover; +using Miningcore.CoinMarketCap; namespace Miningcore; @@ -122,6 +126,9 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType() .SingleInstance(); + builder.RegisterType() + .SingleInstance(); + builder.RegisterType() .SingleInstance(); @@ -213,6 +220,7 @@ protected override void Load(ContainerBuilder builder) ////////////////////// // Handshake + builder.RegisterType(); ////////////////////// @@ -222,6 +230,7 @@ protected override void Load(ContainerBuilder builder) ////////////////////// // Nexa + builder.RegisterType(); ////////////////////// @@ -229,6 +238,21 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType(); + ////////////////////// + // Warthog + + builder.RegisterType(); + + ////////////////////// + // Xelis + + builder.RegisterType(); + + ////////////////////// + // Zano + + builder.RegisterType(); + base.Load(builder); } } diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumConstants.cs b/src/Miningcore/Blockchain/Alephium/AlephiumConstants.cs index ce778a4289..51a2068805 100644 --- a/src/Miningcore/Blockchain/Alephium/AlephiumConstants.cs +++ b/src/Miningcore/Blockchain/Alephium/AlephiumConstants.cs @@ -28,6 +28,7 @@ public static class AlephiumConstants // Socket miner API public const int MessageHeaderSize = 4; // 4 bytes body length + public const byte MiningProtocolVersion = 0x01; public const byte JobsMessageType = 0x00; public const byte SubmitResultMessageType = 0x01; public const byte SubmitBlockMessageType = 0x00; diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumJob.cs b/src/Miningcore/Blockchain/Alephium/AlephiumJob.cs index f12a186560..810d05b28d 100644 --- a/src/Miningcore/Blockchain/Alephium/AlephiumJob.cs +++ b/src/Miningcore/Blockchain/Alephium/AlephiumJob.cs @@ -33,7 +33,7 @@ public class AlephiumJob private AlephiumJobParams jobParams; private readonly ConcurrentDictionary submissions = new(StringComparer.OrdinalIgnoreCase); - private static readonly IHashAlgorithm hasher = new Blake3IHash(); + private static readonly IHashAlgorithm hasher = new Blake3(); private static byte[] GetBigEndianUInt32(uint value) { @@ -56,18 +56,23 @@ protected bool RegisterSubmit(string nonce) return submissions.TryAdd(key, true); } - public virtual byte[] SerializeCoinbase(string nonce) + public virtual byte[] SerializeCoinbase(string nonce, int socketMiningProtocol = 0) { var nonceBytes = (Span) nonce.HexToByteArray(); var headerBlobBytes = (Span) BlockTemplate.HeaderBlob.HexToByteArray(); var txsBlobBytes = (Span) BlockTemplate.TxsBlob.HexToByteArray(); - + uint blockSize = (uint)nonceBytes.Length + (uint)headerBlobBytes.Length + (uint)txsBlobBytes.Length; - uint messageSize = 4 + 1 + blockSize; // encodedBlockSize(4 bytes) + messageType(1 byte) - + int messagePrefixSize = (socketMiningProtocol > 0) ? 1 + 1 + 4: 4 + 1; // socketMiningProtocol: 0 => encodedBlockSize(4 bytes) + messageType(1 byte) || socketMiningProtocol: 1 => version(1 byte) + messageType(1 byte) + encodedBlockSize(4 bytes) + uint messageSize = (uint)messagePrefixSize + blockSize; + using(var stream = new MemoryStream()) { stream.Write(GetBigEndianUInt32(messageSize)); + + if(socketMiningProtocol > 0) + stream.WriteByte(AlephiumConstants.MiningProtocolVersion); + stream.WriteByte(AlephiumConstants.SubmitBlockMessageType); stream.Write(GetBigEndianUInt32(blockSize)); stream.Write(nonceBytes); diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumJobManager.cs b/src/Miningcore/Blockchain/Alephium/AlephiumJobManager.cs index 5e8975aaa7..1df0e2af84 100644 --- a/src/Miningcore/Blockchain/Alephium/AlephiumJobManager.cs +++ b/src/Miningcore/Blockchain/Alephium/AlephiumJobManager.cs @@ -47,13 +47,13 @@ public AlephiumJobManager( private AlephiumCoinTemplate coin; private AlephiumClient rpc; private string network; - private readonly List validJobs = new(); private readonly IExtraNonceProvider extraNonceProvider; private readonly IMasterClock clock; private AlephiumPoolConfigExtra extraPoolConfig; private AlephiumPaymentProcessingConfigExtra extraPoolPaymentProcessingConfig; protected int maxActiveJobs; private int socketJobMessageBufferSize; + private int socketMiningProtocol = 0; protected IObservable AlephiumSubscribeStratumApiSocketClient(CancellationToken ct, DaemonEndpointConfig endPoint, AlephiumDaemonEndpointConfigExtra extraDaemonEndpoint, object payload = null, @@ -92,6 +92,7 @@ protected IObservable AlephiumSubscribeStratumApiSocket int receivedBytes; // Message + byte messageVersion = AlephiumConstants.MiningProtocolVersion; // only available since node release >= "3.6.0" byte messageType; uint messageLength; @@ -106,6 +107,7 @@ protected IObservable AlephiumSubscribeStratumApiSocket uint jobSize; int fromGroup; int toGroup; + ulong height = 0; uint headerBlobLength; byte[] headerBlob; uint txsBlobLength; @@ -141,8 +143,14 @@ protected IObservable AlephiumSubscribeStratumApiSocket if (bufferArray.Length >= messageLength + AlephiumConstants.MessageHeaderSize) { + if(socketMiningProtocol > 0) + { + messageVersion = reader.ReadByte(); + logger.Debug(() => $"Message version: {messageVersion}"); + } + messageType = reader.ReadByte(); - if (messageType == AlephiumConstants.JobsMessageType) + if (messageVersion == AlephiumConstants.MiningProtocolVersion && messageType == AlephiumConstants.JobsMessageType) { jobSize = ReadBigEndianUInt32(reader); logger.Debug(() => $"Parsing {jobSize} job(s) :D"); @@ -156,8 +164,12 @@ protected IObservable AlephiumSubscribeStratumApiSocket toGroup = (int)ReadBigEndianUInt32(reader); logger.Debug(() => $"fromGroup: {fromGroup} - toGroup: {toGroup}"); - chainInfo = await rpc.GetBlockflowChainInfoAsync(fromGroup, toGroup, cts.Token); - logger.Debug(() => $"Height: {chainInfo?.CurrentHeight + 1}"); + if(socketMiningProtocol == 0) + { + chainInfo = await rpc.GetBlockflowChainInfoAsync(fromGroup, toGroup, cts.Token); + height = (ulong) chainInfo?.CurrentHeight + 1; + logger.Debug(() => $"height: {height}"); + } headerBlobLength = ReadBigEndianUInt32(reader); logger.Debug(() => $"headerBlobLength: {headerBlobLength}"); @@ -174,10 +186,16 @@ protected IObservable AlephiumSubscribeStratumApiSocket targetBlob = reader.ReadBytes((int)targetLength); logger.Debug(() => $"targetBlob: {targetBlob.ToHexString()}"); + if(socketMiningProtocol > 0) + { + height = (ulong)ReadBigEndianUInt32(reader); + logger.Debug(() => $"height: {height}"); + } + alephiumBlockTemplate[index] = new AlephiumBlockTemplate { JobId = NextJobId("X"), - Height = (ulong) chainInfo?.CurrentHeight + 1, + Height = height, Timestamp = clock.Now, FromGroup = fromGroup, ToGroup = toGroup, @@ -196,7 +214,7 @@ protected IObservable AlephiumSubscribeStratumApiSocket } else { - logger.Debug(() => $"Unknown message type, wait for more data..."); + logger.Warn(() => $"Message version: {messageVersion}, expects {AlephiumConstants.MiningProtocolVersion} - Message type: {messageType}, expects {AlephiumConstants.JobsMessageType}, wait for more data..."); break; } } @@ -323,15 +341,6 @@ private async Task UpdateJob(CancellationToken ct, string via = null, Alep job.Init(blockTemplate); - lock(jobLock) - { - validJobs.Insert(0, job); - - // trim active jobs - while(validJobs.Count > maxActiveJobs) - validJobs.RemoveAt(validJobs.Count - 1); - } - if(via != null) logger.Info(() => $"Detected new block {job.BlockTemplate.Height} on chain[{job.BlockTemplate.ChainIndex}] [{via}]"); else @@ -431,8 +440,10 @@ private async Task SubmitBlockAsync(CancellationToken ct, DaemonEndpointCo int receivedBytes; // Message + int messageTypeOffset; byte messageType; int startOffset; + int succeedIndex; byte[] message; logger.Debug(() => $"[Submit Block] - Submitting coinbase"); @@ -444,15 +455,17 @@ private async Task SubmitBlockAsync(CancellationToken ct, DaemonEndpointCo { logger.Debug(() => $"{receivedBytes} byte(s) of data have been received"); - messageType = receiveBuffer[AlephiumConstants.MessageHeaderSize]; + messageTypeOffset = (socketMiningProtocol > 0) ? 1: 0; // socketMiningProtocol: 0 => messageType(1 byte) || socketMiningProtocol: 1 => version(1 byte) + messageType(1 byte) + messageType = receiveBuffer[AlephiumConstants.MessageHeaderSize + messageTypeOffset]; if (messageType == AlephiumConstants.SubmitResultMessageType) { logger.Debug(() => $"[Submit Block] - Response received :D"); - startOffset = AlephiumConstants.MessageHeaderSize + 1; // 1 byte message type + startOffset = AlephiumConstants.MessageHeaderSize + messageTypeOffset + 1; // 1 byte message = new byte[receivedBytes - startOffset]; Buffer.BlockCopy(receiveBuffer, startOffset, message, 0, receivedBytes - startOffset); - succeed = (message[8] == 1); + succeedIndex = (socketMiningProtocol > 0) ? 40: 8; // socketMiningProtocol: 0 => succeed: index[8] || socketMiningProtocol: 1 => succeed: index[40] + succeed = (message[succeedIndex] == 1); break; } } @@ -507,9 +520,20 @@ public async ValueTask SubmitShareAsync(StratumConnection worker, Alephiu AlephiumJob job; - lock(jobLock) + lock(context) { - job = validJobs.FirstOrDefault(x => x.JobId == jobId); + job = context.GetJob(jobId); + + if(job == null) + { + // stupid hack for busted ass IceRiver ASICs. Need to loop + // through job using blockTemplate "FromGroup" & "ToGroup" because they submit jobs with incorrect IDs + if(ValidateIsIceRiverMiner(context.UserAgent)) + job = context.validJobs.ToArray().FirstOrDefault(x => x.BlockTemplate.FromGroup == submitParams.FromGroup && x.BlockTemplate.ToGroup == submitParams.ToGroup); + } + + if(job == null) + logger.Warn(() => $"[{context.Miner}] => jobId: {jobId} - Last known job: {context.validJobs.ToArray().FirstOrDefault()?.JobId}"); } if(job == null) @@ -535,7 +559,7 @@ public async ValueTask SubmitShareAsync(StratumConnection worker, Alephiu // Prepare data for the stratum API socket var daemonEndpoint = daemonEndpoints.First(); var extraDaemonEndpoint = daemonEndpoint.Extra.SafeExtensionDataAs(); - var jobCoinbase = job.SerializeCoinbase(nonce); + var jobCoinbase = job.SerializeCoinbase(nonce, socketMiningProtocol); var acceptResponse = await SubmitBlockAsync(ct, daemonEndpoint, extraDaemonEndpoint, jobCoinbase); @@ -724,7 +748,17 @@ protected override async Task AreDaemonsConnectedAsync(CancellationToken c // update stats if(!string.IsNullOrEmpty(nodeInfo?.BuildInfo.ReleaseVersion)) - BlockchainStats.NodeVersion = nodeInfo?.BuildInfo.ReleaseVersion; + { + BlockchainStats.NodeVersion = nodeInfo.BuildInfo.ReleaseVersion; + + // update socket mining protocol + string numbersOnly = Regex.Replace(nodeInfo.BuildInfo.ReleaseVersion, "[^0-9.]", ""); + string[] numbers = numbersOnly.Split("."); + + // update socket mining protocol + if(numbers.Length >= 2) + socketMiningProtocol = ((Convert.ToUInt32(numbers[0]) > 3) || (Convert.ToUInt32(numbers[0]) == 3 && Convert.ToUInt32(numbers[1]) >= 6)) ? 1: 0; + } if(infosChainParams?.NetworkId != 7) return info?.Count > 0; @@ -767,5 +801,11 @@ private AlephiumJobParams GetJobParamsForStratum() return job?.GetJobParams(); } + public override AlephiumJob GetJobForStratum() + { + var job = currentJob; + return job; + } + #endregion // Overrides } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumPool.cs b/src/Miningcore/Blockchain/Alephium/AlephiumPool.cs index 4a601f127e..70efb855f1 100644 --- a/src/Miningcore/Blockchain/Alephium/AlephiumPool.cs +++ b/src/Miningcore/Blockchain/Alephium/AlephiumPool.cs @@ -40,7 +40,6 @@ public AlephiumPool(IComponentContext ctx, { } - protected AlephiumJobParams currentJobParams; protected AlephiumJobManager manager; private AlephiumPoolConfigExtra extraPoolConfig; private AlephiumCoinTemplate coin; @@ -71,7 +70,7 @@ protected virtual async Task OnHelloAsync(StratumConnection connection, Timestam // [Respect the goddamn standards Nicehack :(] var response = new JsonRpcResponse(data, request.Id); - if(context.IsNicehash || manager.ValidateIsGoldShell(context.UserAgent) || manager.ValidateIsIceRiverMiner(context.UserAgent)) + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) { response.Extra = new Dictionary(); response.Extra["error"] = null; @@ -105,7 +104,7 @@ protected virtual async Task OnSubscribeAsync(StratumConnection connection, Time // [Respect the goddamn standards Nicehack :(] var response = new JsonRpcResponse(connection.ConnectionId, request.Id); - if(context.IsNicehash || manager.ValidateIsGoldShell(context.UserAgent) || manager.ValidateIsIceRiverMiner(context.UserAgent)) + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) { response.Extra = new Dictionary(); response.Extra["error"] = null; @@ -156,7 +155,7 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time // [Respect the goddamn standards Nicehack :(] var response = new JsonRpcResponse(context.IsAuthorized, request.Id); - if(context.IsNicehash || manager.ValidateIsGoldShell(context.UserAgent) || manager.ValidateIsIceRiverMiner(context.UserAgent)) + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) { response.Extra = new Dictionary(); response.Extra["error"] = null; @@ -169,11 +168,10 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time await connection.NotifyAsync(AlephiumStratumMethods.SetExtraNonce, manager.GetSubscriberData(connection)); // log association - logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); + logger.Info(() => $"[{connection.ConnectionId}]{(!string.IsNullOrEmpty(context.UserAgent) ? $"[{context.UserAgent}]" : string.Empty)} Authorized worker {workerValue}"); // extract control vars from password var staticDiff = GetStaticDiffFromPassparts(passParts); - var startDiff = GetStartDiffFromPassparts(passParts); // Nicehash support var nicehashDiff = await GetNicehashStaticMinDiff(context, coin.Name, coin.GetAlgorithmName()); @@ -191,43 +189,21 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using miner supplied difficulty of {staticDiff.Value}"); } - // Start diff - if(startDiff.HasValue) - { - if(context.VarDiff != null && startDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && startDiff.Value > context.Difficulty) - { - context.SetDifficulty(startDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {startDiff.Value}"); - } - else - { - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {context.VarDiff.Config.MinDiff}"); - } - } - - // Static diff - if(staticDiff.HasValue && !startDiff.HasValue) - { - if(context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty) - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(staticDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); - } - else - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {context.VarDiff.Config.MinDiff}"); - } - } - - // send initial difficulty - await connection.NotifyAsync(AlephiumStratumMethods.SetDifficulty, new object[] { context.Difficulty }); - - // send intial job - await SendJob(connection, context, currentJobParams); + // Static diff + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) + { + context.VarDiff = null; // disable vardiff + context.SetDifficulty(staticDiff.Value); + + logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); + } + + var minerJobParams = CreateWorkerJob(connection); + + // send intial update + await SendJob(connection, context, minerJobParams); } else @@ -246,6 +222,21 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time } } + private AlephiumJobParams CreateWorkerJob(StratumConnection connection) + { + var context = connection.ContextAs(); + var maxActiveJobs = extraPoolConfig?.MaxActiveJobs ?? 8; + var job = manager.GetJobForStratum(); + + // update context + lock(context) + { + context.AddJob(job, maxActiveJobs); + } + + return job.GetJobParams(); + } + protected virtual async Task OnSubmitAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) { var request = tsRequest.Value; @@ -284,7 +275,7 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta // [Respect the goddamn standards Nicehack :(] var response = new JsonRpcResponse(true, request.Id); - if(context.IsNicehash || manager.ValidateIsGoldShell(context.UserAgent) || manager.ValidateIsIceRiverMiner(context.UserAgent)) + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) { response.Extra = new Dictionary(); response.Extra["error"] = null; @@ -329,19 +320,14 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta protected virtual async Task OnNewJobAsync(AlephiumJobParams jobParams) { - currentJobParams = jobParams; - logger.Info(() => $"Broadcasting job {jobParams.JobId}"); await Guard(() => ForEachMinerAsync(async (connection, ct) => { var context = connection.ContextAs(); + var minerJobParams = CreateWorkerJob(connection); - // varDiff: if the client has a pending difficulty change, apply it now - if(context.ApplyPendingDifficulty()) - await connection.NotifyAsync(AlephiumStratumMethods.SetDifficulty, new object[] { context.Difficulty }); - - await SendJob(connection, context, currentJobParams); + await SendJob(connection, context, minerJobParams); })); } @@ -360,6 +346,9 @@ private async Task SendJob(StratumConnection connection, AlephiumWorkerContext c TargetBlob = target, }; + // send difficulty + await connection.NotifyAsync(AlephiumStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + // send job await connection.NotifyAsync(AlephiumStratumMethods.MiningNotify, new object[] { jobParamsActual }); } @@ -434,6 +423,7 @@ protected override async Task OnRequestAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) { var request = tsRequest.Value; + var context = connection.ContextAs(); try { @@ -444,9 +434,20 @@ protected override async Task OnRequestAsync(StratumConnection connection, break; case AlephiumStratumMethods.Noop: - var context = connection.ContextAs(); context.LastActivity = clock.Now; - await connection.RespondAsync("1", request.Id); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var responseNoop = new JsonRpcResponse("1", request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + responseNoop.Extra = new Dictionary(); + responseNoop.Extra["error"] = null; + } + + await connection.RespondAsync(responseNoop); break; case AlephiumStratumMethods.Subscribe: @@ -462,7 +463,18 @@ protected override async Task OnRequestAsync(StratumConnection connection, break; case AlephiumStratumMethods.SetGzip: - await connection.RespondAsync(false, request.Id); + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var responseSetGzip = new JsonRpcResponse(false, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + responseSetGzip.Extra = new Dictionary(); + responseSetGzip.Extra["error"] = null; + } + + await connection.RespondAsync(responseSetGzip); break; case AlephiumStratumMethods.SubmitHashrate: @@ -506,11 +518,9 @@ protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, if(context.ApplyPendingDifficulty()) { - // send difficulty - await connection.NotifyAsync(AlephiumStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + var minerJobParams = CreateWorkerJob(connection); - // send job - await SendJob(connection, context, currentJobParams); + await SendJob(connection, context, minerJobParams); } } diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumWorkerContext.cs b/src/Miningcore/Blockchain/Alephium/AlephiumWorkerContext.cs index a6a91d0d92..b90978738f 100644 --- a/src/Miningcore/Blockchain/Alephium/AlephiumWorkerContext.cs +++ b/src/Miningcore/Blockchain/Alephium/AlephiumWorkerContext.cs @@ -1,3 +1,6 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; using Miningcore.Mining; namespace Miningcore.Blockchain.Alephium; @@ -16,15 +19,34 @@ public class AlephiumWorkerContext : WorkerContextBase /// /// Usually a wallet address /// - public string Miner { get; set; } + public override string Miner { get; set; } /// /// Arbitrary worker identififer for miners using multiple rigs /// - public string Worker { get; set; } + public override string Worker { get; set; } /// /// Unique value assigned per worker /// public string ExtraNonce1 { get; set; } + + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); + + public virtual void AddJob(AlephiumJob job, int maxActiveJobs) + { + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); + + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); + } + + public AlephiumJob GetJob(string jobId) + { + return validJobs.ToArray().FirstOrDefault(x => x.JobId == jobId); + } } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/Configuration/AlephiumPaymentProcessingConfigExtra.cs b/src/Miningcore/Blockchain/Alephium/Configuration/AlephiumPaymentProcessingConfigExtra.cs index 05f94e1fe6..abbd19182b 100644 --- a/src/Miningcore/Blockchain/Alephium/Configuration/AlephiumPaymentProcessingConfigExtra.cs +++ b/src/Miningcore/Blockchain/Alephium/Configuration/AlephiumPaymentProcessingConfigExtra.cs @@ -19,7 +19,8 @@ public class AlephiumPaymentProcessingConfigExtra public long? BlockRewardsLockTime { get; set; } /// - /// True to exempt transaction fees from miner rewards + /// If True, miners pay payment tx fees + /// Default: False /// public bool KeepTransactionFees { get; set; } } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/BeamJob.cs b/src/Miningcore/Blockchain/Beam/BeamJob.cs index 0bb17ec917..85a46f71cc 100644 --- a/src/Miningcore/Blockchain/Beam/BeamJob.cs +++ b/src/Miningcore/Blockchain/Beam/BeamJob.cs @@ -3,12 +3,13 @@ using System.Globalization; using System.Numerics; using System.Reflection; -using System.Security.Cryptography; using System.Text; using Miningcore.Blockchain.Bitcoin; using Miningcore.Blockchain.Beam.DaemonResponses; using Miningcore.Configuration; using Miningcore.Contracts; +using Miningcore.Crypto; +using Miningcore.Crypto.Hashing.Algorithms; using Miningcore.Extensions; using Miningcore.Native; using Miningcore.Stratum; @@ -28,7 +29,7 @@ public class BeamJob protected readonly ConcurrentDictionary submissions = new(StringComparer.OrdinalIgnoreCase); protected BeamHash solver; - protected readonly HashAlgorithm sha256 = SHA256.Create(); + protected readonly IHashAlgorithm sha256S = new Sha256S(); private (Share Share, string BlockHex, short stratumError) ProcessShareInternal(StratumConnection worker, string nonce, string solution) @@ -45,7 +46,7 @@ public class BeamJob // hash block-solution Span solutionHash = stackalloc byte[32]; - SHA256.HashData(solutionBytes, solutionHash); + sha256S.Digest(solutionBytes, solutionHash); BigInteger solutionHashValue = new BigInteger(solutionHash, true, true); // calc share-diff diff --git a/src/Miningcore/Blockchain/Beam/BeamJobManager.cs b/src/Miningcore/Blockchain/Beam/BeamJobManager.cs index df716d860d..a4eddaf4cb 100644 --- a/src/Miningcore/Blockchain/Beam/BeamJobManager.cs +++ b/src/Miningcore/Blockchain/Beam/BeamJobManager.cs @@ -65,7 +65,6 @@ public BeamJobManager( private readonly IMasterClock clock; private readonly IExtraNonceProvider extraNonceProvider; protected int maxActiveJobs = 4; - private readonly List validJobs = new(); private BeamPoolConfigExtra extraPoolConfig; public ulong? Forkheight; public ulong? Forkheight2; @@ -227,15 +226,6 @@ protected async Task UpdateJob(CancellationToken ct, string via = null, st job.Init(blockTemplate, blockTemplate.JobId, poolConfig, clusterConfig, clock, solver); - lock(jobLock) - { - validJobs.Insert(0, job); - - // trim active jobs - while(validJobs.Count > maxActiveJobs) - validJobs.RemoveAt(validJobs.Count - 1); - } - currentJob = job; if(via != null) @@ -412,6 +402,12 @@ public object[] GetJobParamsForStratum() return job?.GetJobParamsForStratum() ?? Array.Empty(); } + public override BeamJob GetJobForStratum() + { + var job = currentJob; + return job; + } + #region API-Surface public IObservable Jobs { get; private set; } @@ -505,12 +501,14 @@ public async Task ValidateAddressAsync(string address, CancellationToken c Contract.RequiresNonNull(JobId); Contract.RequiresNonNull(nonce); Contract.RequiresNonNull(solution); + + var context = worker.ContextAs(); BeamJob job; - lock(jobLock) + lock(context) { - job = validJobs.FirstOrDefault(x => x.JobId == JobId); + job = context.GetJob(JobId); } if(job == null) @@ -522,8 +520,6 @@ public async Task ValidateAddressAsync(string address, CancellationToken c if (stratumError != BeamConstants.BeamRpcShareAccepted) return (share, stratumError); - var context = worker.ContextAs(); - // enrich share with common data share.PoolId = poolConfig.Id; share.IpAddress = worker.RemoteEndpoint.Address.ToString(); diff --git a/src/Miningcore/Blockchain/Beam/BeamPool.cs b/src/Miningcore/Blockchain/Beam/BeamPool.cs index 06a622f892..84dbae0269 100644 --- a/src/Miningcore/Blockchain/Beam/BeamPool.cs +++ b/src/Miningcore/Blockchain/Beam/BeamPool.cs @@ -43,6 +43,7 @@ public BeamPool(IComponentContext ctx, } protected BeamJobManager manager; + private BeamPoolConfigExtra extraPoolConfig; private BeamCoinTemplate coin; private async Task OnLoginAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) @@ -74,7 +75,6 @@ private async Task OnLoginAsync(StratumConnection connection, Timestamped= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty)) + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) { context.VarDiff = null; // disable vardiff context.SetDifficulty(staticDiff.Value); @@ -101,12 +103,6 @@ private async Task OnLoginAsync(StratumConnection connection, Timestamped $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); } - // Start diff - if(startDiff.HasValue && (context.VarDiff != null && startDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && startDiff.Value > context.Difficulty)) - { - context.SetDifficulty(startDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {startDiff.Value}"); - } // setup worker context context.IsSubscribed = true; @@ -125,15 +121,15 @@ private async Task OnLoginAsync(StratumConnection connection, Timestamped $"[{connection.ConnectionId}] Authorized worker {workerValue}"); - var currentJobParams = manager.GetJobParamsForStratum(); - logger.Info(() => $"Broadcasting job {currentJobParams[0]}"); + var minerJobParams = CreateWorkerJob(connection); + logger.Info(() => $"Broadcasting job {minerJobParams[0]}"); // response var jobResponse = new BeamJobResponse { - Id = (string) currentJobParams[0], - Height = (ulong) currentJobParams[1], + Id = (string) minerJobParams[0], + Height = (ulong) minerJobParams[1], Difficulty = BeamUtils.PackedDifficulty(connection.Context.Difficulty), - Input = (string) currentJobParams[4], + Input = (string) minerJobParams[4], Nonceprefix = context.ExtraNonce1 }; @@ -164,6 +160,21 @@ private async Task OnLoginAsync(StratumConnection connection, Timestamped(); + var maxActiveJobs = extraPoolConfig?.MaxActiveJobs ?? 4; + var job = manager.GetJobForStratum(); + + // update context + lock(context) + { + context.AddJob(job, maxActiveJobs); + } + + return job.GetJobParamsForStratum(); + } + protected virtual async Task OnSubmitAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) { // Beam stratum API: https://github.com/BeamMW/beam/wiki/Beam-mining-protocol-API-(Stratum) @@ -354,20 +365,19 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta protected async Task OnNewJobAsync(object[] jobParams) { - var currentJobParams = jobParams; - - logger.Info(() => $"Broadcasting job {currentJobParams[0]}"); + logger.Info(() => $"Broadcasting job {jobParams[0]}"); await Guard(() => ForEachMinerAsync(async (connection, ct) => { var context = connection.ContextAs(); + var minerJobParams = CreateWorkerJob(connection); // response var jobResponse = new BeamJobResponse { - Id = (string) currentJobParams[0], - Height = (ulong) currentJobParams[1], + Id = (string) minerJobParams[0], + Height = (ulong) minerJobParams[1], Difficulty = BeamUtils.PackedDifficulty(context.Difficulty), - Input = (string) currentJobParams[4], + Input = (string) minerJobParams[4], Nonceprefix = context.ExtraNonce1 }; @@ -381,6 +391,7 @@ await Guard(() => ForEachMinerAsync(async (connection, ct) => public override void Configure(PoolConfig pc, ClusterConfig cc) { coin = pc.Template.As(); + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); base.Configure(pc, cc); } @@ -467,17 +478,18 @@ protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, { await base.OnVarDiffUpdateAsync(connection, newDiff, ct); - if(connection.Context.ApplyPendingDifficulty()) + var context = connection.ContextAs(); + + if(context.ApplyPendingDifficulty()) { - var currentJobParams = manager.GetJobParamsForStratum(); - var context = connection.ContextAs(); - + var minerJobParams = CreateWorkerJob(connection); + // response var jobResponse = new BeamJobResponse { - Id = (string) currentJobParams[0], - Height = (ulong) currentJobParams[1], + Id = (string) minerJobParams[0], + Height = (ulong) minerJobParams[1], Difficulty = BeamUtils.PackedDifficulty(context.Difficulty), - Input = (string) currentJobParams[4], + Input = (string) minerJobParams[4], Nonceprefix = context.ExtraNonce1 }; diff --git a/src/Miningcore/Blockchain/Beam/BeamWorkerContext.cs b/src/Miningcore/Blockchain/Beam/BeamWorkerContext.cs index 27216fa636..4b16e888bb 100644 --- a/src/Miningcore/Blockchain/Beam/BeamWorkerContext.cs +++ b/src/Miningcore/Blockchain/Beam/BeamWorkerContext.cs @@ -1,3 +1,6 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; using Miningcore.Mining; namespace Miningcore.Blockchain.Beam; @@ -7,15 +10,34 @@ public class BeamWorkerContext : WorkerContextBase /// /// Usually a wallet address /// - public string Miner { get; set; } + public override string Miner { get; set; } /// /// Arbitrary worker identififer for miners using multiple rigs /// - public string Worker { get; set; } + public override string Worker { get; set; } /// /// Unique value assigned per worker /// public string ExtraNonce1 { get; set; } + + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); + + public virtual void AddJob(BeamJob job, int maxActiveJobs) + { + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); + + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); + } + + public BeamJob GetJob(string jobId) + { + return validJobs.ToArray().FirstOrDefault(x => x.JobId == jobId); + } } diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs index a362164107..53f8f122ba 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs @@ -1,7 +1,6 @@ using System.Collections.Concurrent; using System.Globalization; using System.Text; -using System.Security.Cryptography; using Miningcore.Blockchain.Bitcoin.Configuration; using Miningcore.Blockchain.Bitcoin.DaemonResponses; using Miningcore.Configuration; @@ -15,7 +14,6 @@ using Newtonsoft.Json.Linq; using Contract = Miningcore.Contracts.Contract; using Transaction = NBitcoin.Transaction; -using System.Numerics; namespace Miningcore.Blockchain.Bitcoin; @@ -43,8 +41,6 @@ public class BitcoinJob protected string coinbaseInitialHex; protected string[] merkleBranchesHex; protected MerkleTree mt; - protected string[] merkleSegwitBranchesHex; - protected MerkleTree mtSegwit; /////////////////////////////////////////// // GetJobParams related properties @@ -80,59 +76,6 @@ protected virtual void BuildMerkleBranches() .ToArray(); } - private static byte[] Sha256Double(byte[] input) - { - using (var sha256 = SHA256.Create()) - { - byte[] hash1 = sha256.ComputeHash(input); - byte[] hash2 = sha256.ComputeHash(hash1); - return hash2; - } - } - - private MerkleTree BuildSegwitMerkleBranches() - { - var segwitTransactionHashes = BlockTemplate.Transactions - .Where(tx => IsSegWitTransaction(tx)) - .Select(tx => (tx.TxId ?? tx.Hash) - .HexToByteArray() - .ReverseInPlace()) - .ToArray(); - - // Build Merkle Tree with SegWit transactions - return new MerkleTree(segwitTransactionHashes); - } - - private bool IsSegWitTransaction(BitcoinBlockTransaction tx) - { - // Convert hex string to byte array - byte[] txBytes = HexStringToByteArray(tx.Data); - - // Convert byte array to hex string - string hexString = ByteArrayToHexString(txBytes); - - // Parse the transaction using NBitcoin - var transaction = Transaction.Parse(hexString, Network.Main); - - return transaction.HasWitness; - } - - private byte[] HexStringToByteArray(string hex) - { - int length = hex.Length; - byte[] bytes = new byte[length / 2]; - for (int i = 0; i < length; i += 2) - { - bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); - } - return bytes; - } - - private string ByteArrayToHexString(byte[] bytes) - { - return BitConverter.ToString(bytes).Replace("-", string.Empty); - } - protected virtual void BuildCoinbase() { // generate script parts @@ -244,35 +187,6 @@ protected virtual byte[] SerializeOutputTransaction(Transaction tx) raw = BlockTemplate.DefaultWitnessCommitment.HexToByteArray(); rawLength = (uint) raw.Length; - if (coin.Symbol == "RVH" || coin.Symbol == "ANOK") - { - // Compute witness commitment - raw = BlockTemplate.DefaultWitnessCommitment.HexToByteArray(); - byte[] witnessRoot = raw; - byte[] witnessNonce = new byte[32]; - - // Build Merkle Tree - var mtSegwit = BuildSegwitMerkleBranches(); - var merkleRoot = mtSegwit.WithFirst(new byte[32]); - - // Concatenate witness root and nonce - byte[] witnessRootAndNonce = new byte[witnessRoot.Length + witnessNonce.Length]; - Buffer.BlockCopy(witnessRoot, 0, witnessRootAndNonce, 0, witnessRoot.Length); - Buffer.BlockCopy(witnessNonce, 0, witnessRootAndNonce, witnessRoot.Length, witnessNonce.Length); - - // Generate SHA256^2 hash - byte[] hash = Sha256Double(witnessRootAndNonce); - - // Create scriptPubKey - byte[] magic = new byte[] { 0xaa, 0x21, 0xa9, 0xed }; - byte[] scriptPubKey = new byte[36]; - Buffer.BlockCopy(magic, 0, scriptPubKey, 0, magic.Length); - Buffer.BlockCopy(hash, 0, scriptPubKey, magic.Length, hash.Length); - - raw = scriptPubKey; - rawLength = (uint)raw.Length; - } - bs.ReadWrite(ref amount); bs.ReadWriteAsVarInt(ref rawLength); bs.ReadWrite(raw); @@ -329,13 +243,13 @@ protected virtual Transaction CreateOutputTransaction() if(coin.HasMasterNodes) rewardToPool = CreateMasternodeOutputs(tx, rewardToPool); - if(coin.HasFounderFee) + if (coin.HasFounderFee) rewardToPool = CreateFounderOutputs(tx, rewardToPool); - if(coin.HasMinerDevFund) - rewardToPool = CreateMinerDevFundOutputs(tx, rewardToPool); + if(coin.HasFortuneReward) + rewardToPool = CreateFortuneOutputs(tx, rewardToPool); - if(coin.HasMinerFund) + if (coin.HasMinerFund) rewardToPool = CreateMinerFundOutputs(tx, rewardToPool); if(coin.HasCommunityAddress) @@ -344,17 +258,8 @@ protected virtual Transaction CreateOutputTransaction() if(coin.HasCoinbaseDevReward) rewardToPool = CreateCoinbaseDevRewardOutputs(tx, rewardToPool); - if(coin.HasFoundation) - rewardToPool = CreateFoundationOutputs(tx, rewardToPool); - - if(coin.HasCommunity) - rewardToPool = CreateCommunityOutputs(tx, rewardToPool); - - if(coin.HasDataMining) - rewardToPool = CreateDataMiningOutputs(tx, rewardToPool); - - if(coin.HasDeveloper) - rewardToPool = CreateDeveloperOutputs(tx, rewardToPool); + if(coin.HasCoinbaseStakingReward) + rewardToPool = CreateCoinbaseStakingRewardOutputs(tx, rewardToPool); // Remaining amount goes to pool tx.Outputs.Add(rewardToPool, poolAddressDestination); @@ -411,7 +316,7 @@ protected byte[] SerializeHeader(Span coinbaseHash, uint nTime, uint nonce Nonce = nonce }; - return blockHeader.ToBytes(); + return blockHeader.ToBytes(); } protected virtual (Share Share, string BlockHex) ProcessShareInternal( @@ -432,8 +337,7 @@ protected virtual (Share Share, string BlockHex) ProcessShareInternal( var headerValue = new uint256(headerHash); // calc share-diff - var diff1 = coin.Diff1 != null ? BigInteger.Parse(coin.Diff1, NumberStyles.HexNumber) : BitcoinConstants.Diff1; // ?????Bitcoin?? - var shareDiff = (double) new BigRational(diff1, headerHash.ToBigInteger()) * shareMultiplier; + var shareDiff = (double) new BigRational(BitcoinConstants.Diff1, headerHash.ToBigInteger()) * shareMultiplier; var stratumDifficulty = context.Difficulty; var ratio = shareDiff / stratumDifficulty; @@ -524,11 +428,10 @@ protected virtual byte[] SerializeBlock(byte[] header, byte[] coinbase) { var separator = new byte[] { 0x01 }; var mweb = BlockTemplate.Extra.SafeExtensionDataAs(); - if (mweb != null && mweb.Mweb != null) { - var mwebRaw = mweb.Mweb.HexToByteArray(); - bs.ReadWrite(separator); - bs.ReadWrite(mwebRaw); - } + var mwebRaw = mweb.Mweb.HexToByteArray(); + + bs.ReadWrite(separator); + bs.ReadWrite(mwebRaw); } return stream.ToArray(); @@ -569,12 +472,12 @@ protected virtual Money CreateMasternodeOutputs(Transaction tx, Money reward) { foreach(var masterNode in masternodes) { - if(!string.IsNullOrEmpty(masterNode.Script)) + if(!string.IsNullOrEmpty(masterNode.Payee)) { - Script payeeAddress = new (masterNode.Script.HexToByteArray()); + var payeeDestination = BitcoinUtils.AddressToDestination(masterNode.Payee, network); var payeeReward = masterNode.Amount; - tx.Outputs.Add(payeeReward, payeeAddress); + tx.Outputs.Add(payeeReward, payeeDestination); reward -= payeeReward; } } @@ -607,98 +510,28 @@ protected virtual Money CreateMasternodeOutputs(Transaction tx, Money reward) #endregion // Masternodes - #region Community - - protected CommunityBlockTemplateExtra communityParameters; - - protected virtual Money CreateCommunityOutputs(Transaction tx, Money reward) - { - if (communityParameters.Community != null) - { - Community[] communitys; - if (communityParameters.Community.Type == JTokenType.Array) - communitys = communityParameters.Community.ToObject(); - else - communitys = new[] { communityParameters.Community.ToObject() }; - - if(communitys != null) - { - foreach(var Community in communitys) - { - if(!string.IsNullOrEmpty(Community.Script)) - { - Script payeeAddress = new (Community.Script.HexToByteArray()); - var payeeReward = Community.Amount; - - tx.Outputs.Add(payeeReward, payeeAddress); - reward -= payeeReward; - } - } - } - } - - return reward; - } - - #endregion //Community - - #region DataMining - - protected DataMiningBlockTemplateExtra dataminingParameters; - - protected virtual Money CreateDataMiningOutputs(Transaction tx, Money reward) - { - if (dataminingParameters.DataMining != null) - { - DataMining[] dataminings; - if (dataminingParameters.DataMining.Type == JTokenType.Array) - dataminings = dataminingParameters.DataMining.ToObject(); - else - dataminings = new[] { dataminingParameters.DataMining.ToObject() }; - - if(dataminings != null) - { - foreach(var DataMining in dataminings) - { - if(!string.IsNullOrEmpty(DataMining.Script)) - { - Script payeeAddress = new (DataMining.Script.HexToByteArray()); - var payeeReward = DataMining.Amount; - - tx.Outputs.Add(payeeReward, payeeAddress); - //reward -= payeeReward; - } - } - } - } - - return reward; - } + #region Fortune - #endregion //DataMining + protected FortuneBlockTemplateExtra fortuneParameters; - #region Developer - - protected DeveloperBlockTemplateExtra developerParameters; - - protected virtual Money CreateDeveloperOutputs(Transaction tx, Money reward) + protected virtual Money CreateFortuneOutputs(Transaction tx, Money reward) { - if (developerParameters.Developer != null) + if(fortuneParameters.Fortune != null) { - Developer[] developers; - if (developerParameters.Developer.Type == JTokenType.Array) - developers = developerParameters.Developer.ToObject(); + Fortune[] fortunes; + if(fortuneParameters.Fortune.Type == JTokenType.Array) + fortunes = fortuneParameters.Fortune.ToObject(); else - developers = new[] { developerParameters.Developer.ToObject() }; + fortunes = new[] { fortuneParameters.Fortune.ToObject() }; - if(developers != null) + if(fortunes != null) { - foreach(var Developer in developers) + foreach(var Fortune in fortunes) { - if(!string.IsNullOrEmpty(Developer.Script)) + if(!string.IsNullOrEmpty(Fortune.Payee)) { - Script payeeAddress = new (Developer.Script.HexToByteArray()); - var payeeReward = Developer.Amount; + var payeeAddress = BitcoinUtils.AddressToDestination(Fortune.Payee, network); + var payeeReward = Fortune.Amount; tx.Outputs.Add(payeeReward, payeeAddress); reward -= payeeReward; @@ -710,7 +543,7 @@ protected virtual Money CreateDeveloperOutputs(Transaction tx, Money reward) return reward; } - #endregion //Developer + #endregion // Fortune #region Founder @@ -730,9 +563,9 @@ protected virtual Money CreateFounderOutputs(Transaction tx, Money reward) { foreach(var Founder in founders) { - if(!string.IsNullOrEmpty(Founder.Script)) + if(!string.IsNullOrEmpty(Founder.Payee)) { - Script payeeAddress = new (Founder.Script.HexToByteArray()); + var payeeAddress = BitcoinUtils.AddressToDestination(Founder.Payee, network); var payeeReward = Founder.Amount; tx.Outputs.Add(payeeReward, payeeAddress); @@ -753,37 +586,20 @@ protected virtual Money CreateFounderOutputs(Transaction tx, Money reward) protected virtual Money CreateMinerFundOutputs(Transaction tx, Money reward) { + var payeeReward = minerFundParameters.MinimumValue; + if (!string.IsNullOrEmpty(minerFundParameters.Addresses?.FirstOrDefault())) { var payeeAddress = BitcoinUtils.AddressToDestination(minerFundParameters.Addresses[0], network); - var payeeReward = minerFundParameters.MinimumValue; tx.Outputs.Add(payeeReward, payeeAddress); - reward -= payeeReward; } - return reward; - } - - #endregion // Minerfund - - #region MinerDevfund + reward -= payeeReward; - protected MinerDevFundTemplateExtra minerDevFundParameters; - - protected virtual Money CreateMinerDevFundOutputs(Transaction tx, Money reward) - { - if (!string.IsNullOrEmpty(minerDevFundParameters.Addresses?.FirstOrDefault())) - { - var payeeAddress = BitcoinUtils.AddressToDestination(minerDevFundParameters.Addresses[0], network); - var payeeReward = minerDevFundParameters.MinimumValue; - tx.Outputs.Add(payeeReward, payeeAddress); - reward -= payeeReward; - } return reward; } - #endregion // MinerDevfund - + #endregion // Founder #region CommunityAddress @@ -814,7 +630,7 @@ protected virtual Money CreateCoinbaseDevRewardOutputs(Transaction tx, Money rew { if(!string.IsNullOrEmpty(CBReward.ScriptPubkey)) { - Script payeeAddress = new (CBReward.ScriptPubkey.HexToByteArray()); + Script payeeAddress = new Script(CBReward.ScriptPubkey.HexToByteArray()); var payeeReward = CBReward.Value; tx.Outputs.Add(payeeReward, payeeAddress); } @@ -825,39 +641,23 @@ protected virtual Money CreateCoinbaseDevRewardOutputs(Transaction tx, Money rew #endregion // CoinbaseDevReward - #region Foundation + #region CoinbaseStakingReward - protected FoundationBlockTemplateExtra foundationParameters; + protected CoinbaseStakingRewardTemplateExtra coinbaseStakingRewardParameters; - protected virtual Money CreateFoundationOutputs(Transaction tx, Money reward) + protected virtual Money CreateCoinbaseStakingRewardOutputs(Transaction tx, Money reward) { - if(foundationParameters.Foundation != null) + if(!string.IsNullOrEmpty(coinbaseStakingRewardParameters.PayoutScript?.ScriptPubkey)) { - Foundation[] foundations; - if(foundationParameters.Foundation.Type == JTokenType.Array) - foundations = foundationParameters.Foundation.ToObject(); - else - foundations = new[] { foundationParameters.Foundation.ToObject() }; - - if(foundations != null) - { - foreach(var Foundation in foundations) - { - if(!string.IsNullOrEmpty(Foundation.Payee)) - { - var payeeAddress = BitcoinUtils.AddressToDestination(Foundation.Payee, network); - var payeeReward = Foundation.Amount; - - tx.Outputs.Add(payeeReward, payeeAddress); - reward -= payeeReward; - } - } - } + Script payeeAddress = new Script(coinbaseStakingRewardParameters.PayoutScript.ScriptPubkey.HexToByteArray()); + var payeeReward = coinbaseStakingRewardParameters.MinimumValue; + tx.Outputs.Add(payeeReward, payeeAddress); + reward -= payeeReward; } return reward; } - #endregion // Foundation + #endregion // CoinbaseStakingReward #region API-Surface @@ -929,47 +729,20 @@ public void Init(BlockTemplate blockTemplate, string jobId, if(coin.HasPayee) payeeParameters = BlockTemplate.Extra.SafeExtensionDataAs(); - if(coin.HasCommunity) - communityParameters = BlockTemplate.Extra.SafeExtensionDataAs(); - - if(coin.HasDataMining) - dataminingParameters = BlockTemplate.Extra.SafeExtensionDataAs(); - - if(coin.HasDeveloper) - developerParameters = BlockTemplate.Extra.SafeExtensionDataAs(); - if (coin.HasFounderFee) - { founderParameters = BlockTemplate.Extra.SafeExtensionDataAs(); - if(coin.Symbol == "FTB") - { - if(founderParameters.Extra?.ContainsKey("fortune") == true) - { - founderParameters.Founder = JToken.FromObject(founderParameters.Extra["fortune"]); - } - } - - if(coin.HasDevFee) - { - if(founderParameters.Extra?.ContainsKey("devfee") == true) - { - founderParameters.Founder = JToken.FromObject(founderParameters.Extra["devfee"]); - } - } - } - - if (coin.HasMinerDevFund) - minerDevFundParameters = BlockTemplate.Extra.SafeExtensionDataAs("coinbasetxn", "minerdevfund"); + if(coin.HasFortuneReward) + fortuneParameters = BlockTemplate.Extra.SafeExtensionDataAs(); if (coin.HasMinerFund) minerFundParameters = BlockTemplate.Extra.SafeExtensionDataAs("coinbasetxn", "minerfund"); - if (coin.HasCoinbaseDevReward) + if(coin.HasCoinbaseDevReward) CoinbaseDevRewardParams = BlockTemplate.Extra.SafeExtensionDataAs(); - if (coin.HasFoundation) - foundationParameters = BlockTemplate.Extra.SafeExtensionDataAs(); + if (coin.HasCoinbaseStakingReward) + coinbaseStakingRewardParameters = BlockTemplate.Extra.SafeExtensionDataAs("coinbasetxn", "stakingrewards"); this.coinbaseHasher = coinbaseHasher; this.headerHasher = headerHasher; diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index 189d2f3410..594365179d 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -1,7 +1,6 @@ using Autofac; using Miningcore.Blockchain.Bitcoin.Configuration; using Miningcore.Blockchain.Bitcoin.DaemonResponses; -using Miningcore.Blockchain.Bitcoin.Custom.AdventurecoinJob; using Miningcore.Configuration; using Miningcore.Contracts; using Miningcore.Crypto; @@ -107,12 +106,6 @@ protected RpcResponse GetBlockTemplateFromJson(string json) private BitcoinJob CreateJob() { - switch(coin.Symbol) - { - case "ADVC": - return new AdventurecoinJob(); - } - return new(); } @@ -165,15 +158,6 @@ await GetBlockTemplateAsync(ct) : ShareMultiplier, coin.CoinbaseHasherValue, coin.HeaderHasherValue, !isPoS ? coin.BlockHasherValue : coin.PoSBlockHasherValue ?? coin.BlockHasherValue); - lock(jobLock) - { - validJobs.Insert(0, job); - - // trim active jobs - while(validJobs.Count > maxActiveJobs) - validJobs.RemoveAt(validJobs.Count - 1); - } - if(isNew) { if(via != null) @@ -222,6 +206,12 @@ protected override object GetJobParamsForStratum(bool isNew) return job?.GetJobParams(isNew); } + public override BitcoinJob GetJobForStratum() + { + var job = currentJob; + return job; + } + #region API-Surface public override void Configure(PoolConfig pc, ClusterConfig cc) @@ -281,9 +271,9 @@ public virtual async ValueTask SubmitShareAsync(StratumConnection worker, BitcoinJob job; - lock(jobLock) + lock(context) { - job = validJobs.FirstOrDefault(x => x.JobId == jobId); + job = context.GetJob(jobId); } if(job == null) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index 91610343e4..8a6578022a 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -41,11 +41,10 @@ protected BitcoinJobManagerBase( protected RpcClient rpc; protected readonly IExtraNonceProvider extraNonceProvider; protected const int ExtranonceBytes = 4; - protected int maxActiveJobs = 4; + public int maxActiveJobs { get; protected set; } = 4; protected bool hasLegacyDaemon; protected BitcoinPoolConfigExtra extraPoolConfig; protected BitcoinPoolPaymentProcessingConfigExtra extraPoolPaymentProcessingConfig; - protected readonly List validJobs = new(); protected DateTime? lastJobRebroadcast; protected bool hasSubmitBlockMethod; protected bool isPoS; @@ -548,7 +547,7 @@ protected virtual IDestination AddressToDestination(string address, BitcoinAddre switch(addressType.Value) { case BitcoinAddressType.BechSegwit: - return BitcoinUtils.BechSegwitAddressToDestination(poolConfig.Address, network, extraPoolConfig?.BechPrefix); + return BitcoinUtils.BechSegwitAddressToDestination(poolConfig.Address, network); case BitcoinAddressType.BCash: return BitcoinUtils.BCashAddressToDestination(poolConfig.Address, network); diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs index 298cec77cf..70c077c9d2 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs @@ -217,7 +217,7 @@ public virtual async Task PayoutAsync(IMiningPool pool, Balance[] balances, Canc { var subtractFeesFrom = amounts.Keys.ToArray(); - if(!poolConfig.Template.As().HasMasterNodes || coin.Symbol == "KIIRO" || coin.Symbol == "DDR"|| coin.Symbol == "VORA") + if(!poolConfig.Template.As().HasMasterNodes) { args = new object[] { diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs index a85c6302d9..5136882f40 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPool.cs @@ -64,7 +64,18 @@ protected virtual async Task OnSubscribeAsync(StratumConnection connection, Time .Concat(manager.GetSubscriberData(connection)) .ToArray(); - await connection.RespondAsync(data, request.Id); + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(data, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // setup worker context context.IsSubscribed = true; @@ -81,9 +92,11 @@ protected virtual async Task OnSubscribeAsync(StratumConnection connection, Time context.SetDifficulty(nicehashDiff.Value); } + var minerJobParams = CreateWorkerJob(connection, context.IsSubscribed); + // send intial update await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); - await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); } protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) @@ -111,48 +124,38 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time if(context.IsAuthorized) { + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(context.IsAuthorized, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + // respond - await connection.RespondAsync(context.IsAuthorized, request.Id); + await connection.RespondAsync(response); // log association logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); // extract control vars from password var staticDiff = GetStaticDiffFromPassparts(passParts); - var startDiff = GetStartDiffFromPassparts(passParts); - - // Start diff - if(startDiff.HasValue) - { - if(context.VarDiff != null && startDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && startDiff.Value > context.Difficulty) - { - context.SetDifficulty(startDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {startDiff.Value}"); - } - else - { - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {context.VarDiff.Config.MinDiff}"); - } - } - - // Static diff - if(staticDiff.HasValue && !startDiff.HasValue) - { - if(context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty) - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(staticDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); - } - else - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {context.VarDiff.Config.MinDiff}"); - } - } - await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + + // Static diff + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) + { + context.VarDiff = null; // disable vardiff + context.SetDifficulty(staticDiff.Value); + + logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); + + await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + } } else @@ -171,6 +174,20 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time } } + private object CreateWorkerJob(StratumConnection connection, bool cleanJob) + { + var context = connection.ContextAs(); + var job = manager.GetJobForStratum(); + + // update context + lock(context) + { + context.AddJob(job, manager.maxActiveJobs); + } + + return job.GetJobParams(cleanJob); + } + protected virtual async Task OnSubmitAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) { var request = tsRequest.Value; @@ -203,7 +220,19 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta // submit var share = await manager.SubmitShareAsync(connection, requestParams, ct); - await connection.RespondAsync(true, request.Id); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // publish messageBus.SendMessage(share); @@ -211,7 +240,7 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta // telemetry PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, true); - logger.Info(() => $"[{connection.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty * coin.ShareMultiplier, 9)}"); + logger.Info(() => $"[{connection.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty * coin.ShareMultiplier, 3)}"); // update pool stats if(share.IsBlockCandidate) @@ -233,9 +262,9 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta logger.Info(() => $"[{connection.ConnectionId}] Share rejected: {ex.Message} [{context.UserAgent}]"); // banning - ConsiderBan(connection, context, poolConfig.Banning); + // ConsiderBan(connection, context, poolConfig.Banning); - throw; + //throw; } } @@ -244,12 +273,24 @@ private async Task OnSuggestDifficultyAsync(StratumConnection connection, Timest var request = tsRequest.Value; var context = connection.ContextAs(); + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + // acknowledge - await connection.RespondAsync(true, request.Id); + await connection.RespondAsync(response); try { - var requestedDiff = (double) Convert.ChangeType(request.Params, TypeCode.Double)!; + var requestParams = request.ParamsAs(); + var requestedDiff = (double) Convert.ChangeType(requestParams.FirstOrDefault()?.ToString().Trim(), typeof(double)); // client may suggest higher-than-base difficulty, but not a lower one var poolEndpoint = poolConfig.Ports[connection.LocalEndpoint.Port]; @@ -296,13 +337,19 @@ private async Task OnConfigureMiningAsync(StratumConnection connection, Timestam } } + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] var response = new JsonRpcResponse(result, request.Id); - response.Extra = new Dictionary(); - response.Extra["error"] = null; - await connection.RespondAsync(response); + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } - } + await connection.RespondAsync(response); + } private void ConfigureVersionRolling(StratumConnection connection, BitcoinWorkerContext context, IReadOnlyDictionary extensionParams, Dictionary result) @@ -352,13 +399,14 @@ protected virtual async Task OnNewJobAsync(object jobParams) await Guard(() => ForEachMinerAsync(async (connection, ct) => { var context = connection.ContextAs(); + var minerJobParams = CreateWorkerJob(connection, (bool) ((object[]) jobParams)[^1]); // varDiff: if the client has a pending difficulty change, apply it now if(context.ApplyPendingDifficulty()) await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); // send job - await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); })); } @@ -459,7 +507,20 @@ protected override async Task OnRequestAsync(StratumConnection connection, break; case BitcoinStratumMethods.ExtraNonceSubscribe: - await connection.RespondAsync(true, request.Id); + var context = connection.ContextAs(); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); break; case BitcoinStratumMethods.GetTransactions: @@ -490,8 +551,10 @@ protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, if(connection.Context.ApplyPendingDifficulty()) { + var minerJobParams = CreateWorkerJob(connection, (bool) ((object[]) currentJobParams)[^1]); + await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { connection.Context.Difficulty }); - await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); } } diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinUtils.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinUtils.cs index d5677f6b5a..9a41a1bab4 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinUtils.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinUtils.cs @@ -25,9 +25,9 @@ public static IDestination AddressToDestination(string address, Network expected return result; } - public static IDestination BechSegwitAddressToDestination(string address, Network expectedNetwork, string bechPrefix) + public static IDestination BechSegwitAddressToDestination(string address, Network expectedNetwork) { - var encoder = Encoders.Bech32(bechPrefix); + var encoder = expectedNetwork.GetBech32Encoder(Bech32Type.WITNESS_PUBKEY_ADDRESS, true); var decoded = encoder.Decode(address, out var witVersion); var result = new WitKeyId(decoded); diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinWorkerContext.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinWorkerContext.cs index 6304081b8a..4299b58862 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinWorkerContext.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinWorkerContext.cs @@ -1,3 +1,6 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; using Miningcore.Mining; namespace Miningcore.Blockchain.Bitcoin; @@ -7,12 +10,12 @@ public class BitcoinWorkerContext : WorkerContextBase /// /// Usually a wallet address /// - public string Miner { get; set; } + public override string Miner { get; set; } /// /// Arbitrary worker identififer for miners using multiple rigs /// - public string Worker { get; set; } + public override string Worker { get; set; } /// /// Unique value assigned per worker @@ -23,4 +26,23 @@ public class BitcoinWorkerContext : WorkerContextBase /// Mask for version-rolling (Overt ASIC-Boost) /// public uint? VersionRollingMask { get; internal set; } + + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); + + public virtual void AddJob(BitcoinJob job, int maxActiveJobs) + { + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); + + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); + } + + public BitcoinJob GetJob(string jobId) + { + return validJobs.ToArray().FirstOrDefault(x => x.JobId == jobId); + } } diff --git a/src/Miningcore/Blockchain/Bitcoin/Configuration/BitcoinPoolConfigExtra.cs b/src/Miningcore/Blockchain/Bitcoin/Configuration/BitcoinPoolConfigExtra.cs index e3445d70fc..fd4788ab11 100644 --- a/src/Miningcore/Blockchain/Bitcoin/Configuration/BitcoinPoolConfigExtra.cs +++ b/src/Miningcore/Blockchain/Bitcoin/Configuration/BitcoinPoolConfigExtra.cs @@ -7,8 +7,6 @@ public class BitcoinPoolConfigExtra { public BitcoinAddressType AddressType { get; set; } = BitcoinAddressType.Legacy; - public string BechPrefix { get; set; } = "bc"; - /// /// Maximum number of tracked jobs. /// Default: 12 - you should increase this value if your blockrefreshinterval is higher than 300ms diff --git a/src/Miningcore/Blockchain/Bitcoin/Custom/AdventurecoinJob.cs b/src/Miningcore/Blockchain/Bitcoin/Custom/AdventurecoinJob.cs deleted file mode 100644 index 23918096c2..0000000000 --- a/src/Miningcore/Blockchain/Bitcoin/Custom/AdventurecoinJob.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.Collections.Concurrent; -using System.Globalization; -using System.Text; -using System.Security.Cryptography; -using Miningcore.Blockchain.Bitcoin; -using Miningcore.Blockchain.Bitcoin.Configuration; -using Miningcore.Blockchain.Bitcoin.DaemonResponses; -using Miningcore.Configuration; -using Miningcore.Crypto; -using Miningcore.Extensions; -using Miningcore.Stratum; -using Miningcore.Time; -using Miningcore.Util; -using NBitcoin; -using NBitcoin.DataEncoders; -using Newtonsoft.Json.Linq; -using Contract = Miningcore.Contracts.Contract; -using Transaction = NBitcoin.Transaction; -using System.Numerics; - -namespace Miningcore.Blockchain.Bitcoin.Custom.AdventurecoinJob; - -public class AdventurecoinJob : BitcoinJob -{ - - #region Developer - - protected override Money CreateDeveloperOutputs(Transaction tx, Money reward) - { - if (developerParameters.Developer != null) - { - Developer[] developers; - if (developerParameters.Developer.Type == JTokenType.Array) - developers = developerParameters.Developer.ToObject(); - else - developers = new[] { developerParameters.Developer.ToObject() }; - - if(developers != null) - { - foreach(var Developer in developers) - { - if(!string.IsNullOrEmpty(Developer.Script)) - { - Script payeeAddress = new (Developer.Script.HexToByteArray()); - var payeeReward = Developer.Amount; - - tx.Outputs.Add(payeeReward, payeeAddress); - } - } - } - } - - return reward; - } - - #endregion //Developer -} diff --git a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/CoinbaseDevReward.cs b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/CoinbaseDevReward.cs index e01c52a3dd..b38a17a674 100644 --- a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/CoinbaseDevReward.cs +++ b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/CoinbaseDevReward.cs @@ -9,11 +9,12 @@ namespace Miningcore.Blockchain.Bitcoin.DaemonResponses public class CoinbaseDevReward { public string ScriptPubkey { get; set; } - public long Value { get; set; } + public long Value { get; set; } } public class CoinbaseDevRewardTemplateExtra { + [JsonProperty("coinbasedevreward")] public JToken CoinbaseDevReward { get; set; } } -} \ No newline at end of file +} diff --git a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/CoinbaseStakingReward.cs b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/CoinbaseStakingReward.cs new file mode 100644 index 0000000000..902588ce71 --- /dev/null +++ b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/CoinbaseStakingReward.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Miningcore.Blockchain.Bitcoin.DaemonResponses +{ + public class CoinbaseStakingRewardPayoutScript + { + [JsonProperty("hex")] + public string ScriptPubkey { get; set; } + } + + public class CoinbaseStakingRewardTemplateExtra + { + public CoinbaseStakingRewardPayoutScript PayoutScript { get; set; } + public ulong MinimumValue { get; set; } + } +} diff --git a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Community.cs b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Community.cs deleted file mode 100644 index 089a37d1a6..0000000000 --- a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Community.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Miningcore.Blockchain.Bitcoin.DaemonResponses -{ - public class Community - { - public string Payee { get; set; } - public string Script { get; set; } - public long Amount { get; set; } - } - - public class CommunityBlockTemplateExtra - { - public JToken Community { get; set; } - - [JsonProperty("community_payments_started")] - public bool CommunityPaymentsStarted { get; set; } - - [JsonExtensionData] - public IDictionary Extra { get; set; } - } -} diff --git a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/DataMining.cs b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/DataMining.cs deleted file mode 100644 index 90d2beb6f3..0000000000 --- a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/DataMining.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Miningcore.Blockchain.Bitcoin.DaemonResponses -{ - public class DataMining - { - public string Payee { get; set; } - public string Script { get; set; } - public long Amount { get; set; } - } - - public class DataMiningBlockTemplateExtra - { - public JToken DataMining { get; set; } - - [JsonProperty("datamining_payments_started")] - public bool DataMiningPaymentsStarted { get; set; } - - [JsonExtensionData] - public IDictionary Extra { get; set; } - } -} diff --git a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Developer.cs b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Developer.cs deleted file mode 100644 index 29ff13ea84..0000000000 --- a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Developer.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Miningcore.Blockchain.Bitcoin.DaemonResponses -{ - public class Developer - { - public string Payee { get; set; } - public string Script { get; set; } - public long Amount { get; set; } - } - - public class DeveloperBlockTemplateExtra - { - public JToken Developer{ get; set; } - - [JsonProperty("developer_payments_started")] - public bool DeveloperPaymentsStarted { get; set; } - - [JsonExtensionData] - public IDictionary Extra { get; set; } - } -} diff --git a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Foundation.cs b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Fortune.cs similarity index 54% rename from src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Foundation.cs rename to src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Fortune.cs index 8c82c33741..beafadbbbe 100644 --- a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Foundation.cs +++ b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Fortune.cs @@ -1,20 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Text; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace Miningcore.Blockchain.Bitcoin.DaemonResponses { - public class Foundation + public class Fortune { public string Payee { get; set; } public string Script { get; set; } public long Amount { get; set; } } - public class FoundationBlockTemplateExtra + public class FortuneBlockTemplateExtra { - public JToken Foundation { get; set; } + public JToken Fortune { get; set; } + + [JsonProperty("fortune_payments_started")] + public bool FortunePaymentsStarted { get; set; } } } diff --git a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Founder.cs b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Founder.cs index 6238156524..ae55b3f51a 100644 --- a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Founder.cs +++ b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Founder.cs @@ -16,8 +16,5 @@ public class FounderBlockTemplateExtra [JsonProperty("founder_payments_started")] public bool FounderPaymentsStarted { get; set; } - - [JsonExtensionData] - public IDictionary Extra { get; set; } } } diff --git a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/MinerDevFund.cs b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/MinerDevFund.cs deleted file mode 100644 index f43a9fe302..0000000000 --- a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/MinerDevFund.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Miningcore.Blockchain.Bitcoin.DaemonResponses -{ - public class MinerDevFundTemplateExtra - { - public string[] Addresses { get; set; } - public ulong MinimumValue { get; set; } - } -} diff --git a/src/Miningcore/Blockchain/Conceal/ConcealJob.cs b/src/Miningcore/Blockchain/Conceal/ConcealJob.cs index c699b50f00..469b871338 100644 --- a/src/Miningcore/Blockchain/Conceal/ConcealJob.cs +++ b/src/Miningcore/Blockchain/Conceal/ConcealJob.cs @@ -73,6 +73,8 @@ private string EncodeTarget(double difficulty, int size = 4) if(padLength > 0) bytes.CopyTo(padded.Slice(padLength, bytes.Length)); + else + bytes.Slice(bytes.Length - padded.Length, padded.Length).CopyTo(padded); padded = padded[..size]; padded.Reverse(); diff --git a/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs b/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs index 0693fa5385..3ce6da4876 100644 --- a/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs +++ b/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs @@ -193,6 +193,23 @@ private async Task SubmitBlockAsync(Share share, string blobHex, string bl return true; } + public void PrepareWorkerJob(ConcealWorkerJob workerJob, out string blob, out string target) + { + blob = null; + target = null; + + var job = currentJob; + + if(job != null) + job.PrepareWorkerJob(workerJob, out blob, out target); + } + + public override ConcealJob GetJobForStratum() + { + var job = currentJob; + return job; + } + #region API-Surface public IObservable Blocks { get; private set; } @@ -284,22 +301,6 @@ public bool ValidateAddress(string address) public BlockchainStats BlockchainStats { get; } = new(); - public void PrepareWorkerJob(ConcealWorkerJob workerJob, out string blob, out string target) - { - blob = null; - target = null; - - var job = currentJob; - - if(job != null) - { - lock(job) - { - job.PrepareWorkerJob(workerJob, out blob, out target); - } - } - } - public async ValueTask SubmitShareAsync(StratumConnection worker, ConcealSubmitShareRequest request, ConcealWorkerJob workerJob, CancellationToken ct) { @@ -391,14 +392,20 @@ protected override async Task AreDaemonsHealthyAsync(CancellationToken ct) // test daemons try { - var response = await restClient.Get(ConcealConstants.DaemonRpcGetInfoLocation, ct); - if(response?.Status != "OK") + var request = new GetBlockTemplateRequest { - logger.Debug(() => $"conceald daemon did not responded..."); - return false; - } + WalletAddress = poolConfig.Address, + ReserveSize = ConcealConstants.ReserveSize + }; + + var response = await rpc.ExecuteAsync(logger, + ConcealCommands.GetBlockTemplate, ct, request); + + if(response.Error != null) + logger.Debug(() => $"conceald daemon response: {response.Error.Message} (Code {response.Error.Code})"); - logger.Debug(() => $"{response?.Status} - Incoming: {response?.IncomingConnectionsCount} - Outgoing: {response?.OutgoingConnectionsCount})"); + if(response.Error is {Code: -9}) + return false; } catch(Exception) @@ -467,30 +474,32 @@ protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) do { - var request = new GetBlockTemplateRequest + try { - WalletAddress = poolConfig.Address, - ReserveSize = ConcealConstants.ReserveSize - }; + var request = new GetBlockTemplateRequest + { + WalletAddress = poolConfig.Address, + ReserveSize = ConcealConstants.ReserveSize + }; - var response = await rpc.ExecuteAsync(logger, - ConcealCommands.GetBlockTemplate, ct, request); - - if(response.Error != null) - logger.Debug(() => $"conceald daemon response: {response.Error.Message} (Code {response.Error.Code})"); + var response = await rpc.ExecuteAsync(logger, + ConcealCommands.GetBlockTemplate, ct, request); - var info = await walletRpc.ExecuteAsync(logger, - ConcealWalletCommands.GetStatus, ct, new {}); + if(response.Error != null) + logger.Debug(() => $"conceald daemon response: {response.Error.Message} (Code {response.Error.Code})"); - if(info.Error != null) - logger.Debug(() => $"walletd daemon response: {info.Error.Message} (Code {info.Error.Code})"); + var info = await restClient.Get(ConcealConstants.DaemonRpcGetInfoLocation, ct); - var isSynched = ((response.Error is not {Code: -9}) && (info.Response?.BlockCount >= info.Response?.KnownBlockCount)); + if((response.Error is not {Code: -9}) && (response.Response?.Height >= info.Height)) + { + logger.Info(() => "All daemons synched with blockchain"); + break; + } + } - if(isSynched) + catch(Exception e) { - logger.Info(() => "All daemons synched with blockchain"); - break; + logger.Error(e); } if(!syncPendingNotificationShown) diff --git a/src/Miningcore/Blockchain/Conceal/ConcealPool.cs b/src/Miningcore/Blockchain/Conceal/ConcealPool.cs index d9bf32cecd..6247dce03b 100644 --- a/src/Miningcore/Blockchain/Conceal/ConcealPool.cs +++ b/src/Miningcore/Blockchain/Conceal/ConcealPool.cs @@ -91,7 +91,6 @@ private async Task OnLoginAsync(StratumConnection connection, Timestamped $"[{connection.ConnectionId}] Nicehash detected. Using miner supplied difficulty of {staticDiff.Value}"); } - // Start diff - if(startDiff.HasValue) - { - if(context.VarDiff != null && startDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && startDiff.Value > context.Difficulty) - { - context.SetDifficulty(startDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {startDiff.Value}"); - } - else - { - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {context.VarDiff.Config.MinDiff}"); - } - } - - // Static diff - if(staticDiff.HasValue && !startDiff.HasValue) - { - if(context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty) - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(staticDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); - } - else - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {context.VarDiff.Config.MinDiff}"); - } - } + // Static diff + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) + { + context.VarDiff = null; // disable vardiff + context.SetDifficulty(staticDiff.Value); + + logger.Info(() => $"[{connection.ConnectionId}] Static difficulty set to {staticDiff.Value}"); + } // respond var loginResponse = new ConcealLoginResponse @@ -148,7 +126,18 @@ private async Task OnLoginAsync(StratumConnection connection, Timestamped(loginResponse, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // log association if(!string.IsNullOrEmpty(context.Worker)) @@ -186,9 +175,21 @@ private async Task OnGetJobAsync(StratumConnection connection, Timestamped(job, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + // respond + await connection.RespondAsync(response); } private ConcealJobParams CreateWorkerJob(StratumConnection connection) @@ -199,7 +200,7 @@ private ConcealJobParams CreateWorkerJob(StratumConnection connection) 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(target)) return null; var result = new ConcealJobParams @@ -216,7 +217,7 @@ private ConcealJobParams CreateWorkerJob(StratumConnection connection) // update context lock(context) { - context.AddJob(job); + context.AddJob(job, 4); } return result; @@ -232,6 +233,10 @@ private async Task OnSubmitAsync(StratumConnection connection, Timestamped(); // validate worker - if(connection.ConnectionId != submitRequest?.WorkerId || !context.IsAuthorized) - throw new StratumException(StratumError.MinusOne, "unauthorized"); + if(connection.ConnectionId != submitRequest?.WorkerId) + throw new StratumException(StratumError.MinusOne, "cheater"); // recognize activity context.LastActivity = clock.Now; @@ -257,7 +262,7 @@ private async Task OnSubmitAsync(StratumConnection connection, Timestamped(new ConcealResponseBase(), request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // publish messageBus.SendMessage(share); @@ -409,7 +426,19 @@ protected override async Task OnRequestAsync(StratumConnection connection, // For some reasons, we would never send a reply here :/ // But the official XMRig documentation is explicit, we should reply: https://xmrig.com/docs/extensions/keepalive // XMRig is such a gift, i wish more mining pool operators were like them and valued open-source, the same way the XMRig devs do - await connection.RespondAsync(new ConcealKeepAliveResponse(), request.Id); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(new ConcealKeepAliveResponse(), request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); break; default: diff --git a/src/Miningcore/Blockchain/Conceal/ConcealWorkerContext.cs b/src/Miningcore/Blockchain/Conceal/ConcealWorkerContext.cs index 9539d0bfd7..e969db4ce6 100644 --- a/src/Miningcore/Blockchain/Conceal/ConcealWorkerContext.cs +++ b/src/Miningcore/Blockchain/Conceal/ConcealWorkerContext.cs @@ -1,3 +1,6 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; using Miningcore.Mining; namespace Miningcore.Blockchain.Conceal; @@ -8,25 +11,29 @@ public class ConcealWorkerContext : WorkerContextBase /// Usually a wallet address /// NOTE: May include paymentid (seperated by a dot .) /// - public string Miner { get; set; } + public override string Miner { get; set; } /// /// Arbitrary worker identififer for miners using multiple rigs /// - public string Worker { get; set; } + public override string Worker { get; set; } - private List validJobs { get; } = new(); + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); - public void AddJob(ConcealWorkerJob job) + public virtual void AddJob(ConcealWorkerJob job, int maxActiveJobs) { - validJobs.Insert(0, job); + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); - while(validJobs.Count > 4) - validJobs.RemoveAt(validJobs.Count - 1); + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); } - public ConcealWorkerJob FindJob(string jobId) + public ConcealWorkerJob GetJob(string jobId) { - return validJobs.FirstOrDefault(x => x.Id == jobId); + return validJobs.ToArray().FirstOrDefault(x => x.Id == jobId); } } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Cryptonote/Configuration/CryptonotePoolPaymentProcessingConfigExtra.cs b/src/Miningcore/Blockchain/Cryptonote/Configuration/CryptonotePoolPaymentProcessingConfigExtra.cs index 9c7a52a385..fd4faac5d0 100644 --- a/src/Miningcore/Blockchain/Cryptonote/Configuration/CryptonotePoolPaymentProcessingConfigExtra.cs +++ b/src/Miningcore/Blockchain/Cryptonote/Configuration/CryptonotePoolPaymentProcessingConfigExtra.cs @@ -3,4 +3,10 @@ namespace Miningcore.Blockchain.Cryptonote.Configuration; public class CryptonotePoolPaymentProcessingConfigExtra { public decimal MinimumPaymentToPaymentId { get; set; } + + /// + /// Maximum of simultaneous destination address in a single transaction + /// Default: 16 + /// + public int? MaximumDestinationPerTransfer { get; set; } } diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteConstants.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteConstants.cs index 33cda594f0..284fbdf409 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteConstants.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteConstants.cs @@ -42,28 +42,6 @@ public static class CryptonoteConstants public const decimal StaticTransactionFeeReserve = 0.03m; // in monero } -public static class GntlConstants -{ - public const decimal GntlMiningRewardInitial = 0.99m; -} - -public static class MoreloConstants -{ - public const decimal MoreloReserveRewardInitial = 5.555m; // MiningReward = BlockReward - ReserveReward - public const decimal MoreloStaticTransactionFeeReserve = 1.0m; // Deduct static reserve for tx fees -} - -public static class EquilibriaConstants -{ - public const int EquilibriaBlobType = 5; - public const decimal EquilibriaMiningRewardInitial = 0.25m; -} - -public static class ScalaConstants -{ - public const int ScalaBlobType = 14; -} - public static class ZephyrConstants { public const int BlobType = 13; diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs index aa6bdf2935..1dabd1385f 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs @@ -36,9 +36,6 @@ public CryptonoteJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, { { CryptonightHashType.RandomX, (realm, seedHex, data, result, _) => RandomX.CalculateHash(realm, seedHex, data, result) }, { CryptonightHashType.RandomARQ, (realm, seedHex, data, result, _) => RandomARQ.CalculateHash(realm, seedHex, data, result) }, - { CryptonightHashType.RandomSCASH, (realm, seedHex, data, result, _) => RandomSCASH.CalculateHash(realm, seedHex, data, result) }, - { CryptonightHashType.RandomXEQ, (realm, seedHex, data, result, _) => RandomXEQ.CalculateHash(realm, seedHex, data, result) }, - { CryptonightHashType.Panthera, (realm, seedHex, data, result, _) => Panthera.CalculateHash(realm, seedHex, data, result) }, { CryptonightHashType.Cryptonight0, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_0, height) }, { CryptonightHashType.Cryptonight1, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_1, height) }, { CryptonightHashType.Cryptonight2, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_2, height) }, @@ -52,9 +49,8 @@ public CryptonoteJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, { CryptonightHashType.CryptonightGPU, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_GPU, height) }, { CryptonightHashType.CryptonightFast, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_FAST, height) }, { CryptonightHashType.CryptonightXAO, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_XAO, height) }, - { CryptonightHashType.Flex, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, FLEX_KCN, height) }, { CryptonightHashType.Ghostrider, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, GHOSTRIDER_RTM, height) }, - { CryptonightHashType.Mike, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, GHOSTRIDER_MIKE, height) }, + { CryptonightHashType.Mike, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, GHOSTRIDER_MIKE, height) }, { CryptonightHashType.CryptonightLite0, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_LITE_0, height) }, { CryptonightHashType.CryptonightLite1, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_LITE_1, height) }, { CryptonightHashType.CryptonightHeavy, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_HEAVY_0, height) }, @@ -102,6 +98,8 @@ private string EncodeTarget(double difficulty, int size = 4) if(padLength > 0) bytes.CopyTo(padded.Slice(padLength, bytes.Length)); + else + bytes.Slice(bytes.Length - padded.Length, padded.Length).CopyTo(padded); padded = padded[..size]; padded.Reverse(); @@ -213,9 +211,8 @@ public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out Span blockHash = stackalloc byte[32]; // Not all Cryptonote coins are equal - if(blobType == ZephyrConstants.BlobType || blobType == EquilibriaConstants.EquilibriaBlobType || blobType == ScalaConstants.ScalaBlobType) + if(blobType == ZephyrConstants.BlobType) CryptonoteBindings.GetBlockId(blob, blockHash, blobType); - else ComputeBlockHash(blobConverted, blockHash); diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs index 0b539ebff8..5afea29b0b 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs @@ -183,90 +183,6 @@ private void UpdateHashParams(GetBlockTemplateResponse blockTemplate) break; } - - case CryptonightHashType.RandomSCASH: - { - // detect seed hash change - if(currentSeedHash != blockTemplate.SeedHash) - { - logger.Info(()=> $"Detected new seed hash {blockTemplate.SeedHash} starting @ height {blockTemplate.Height}"); - - if(poolConfig.EnableInternalStratum == true) - { - RandomSCASH.WithLock(() => - { - // delete old seed - if(currentSeedHash != null) - RandomSCASH.DeleteSeed(randomXRealm, currentSeedHash); - - // activate new one - currentSeedHash = blockTemplate.SeedHash; - RandomSCASH.CreateSeed(randomXRealm, currentSeedHash, randomXFlagsOverride, randomXFlagsAdd, extraPoolConfig.RandomXVMCount); - }); - } - - else - currentSeedHash = blockTemplate.SeedHash; - } - - break; - } - - case CryptonightHashType.RandomXEQ: - { - // detect seed hash change - if(currentSeedHash != blockTemplate.SeedHash) - { - logger.Info(()=> $"Detected new seed hash {blockTemplate.SeedHash} starting @ height {blockTemplate.Height}"); - - if(poolConfig.EnableInternalStratum == true) - { - RandomXEQ.WithLock(() => - { - // delete old seed - if(currentSeedHash != null) - RandomXEQ.DeleteSeed(randomXRealm, currentSeedHash); - - // activate new one - currentSeedHash = blockTemplate.SeedHash; - RandomXEQ.CreateSeed(randomXRealm, currentSeedHash, randomXFlagsOverride, randomXFlagsAdd, extraPoolConfig.RandomXVMCount); - }); - } - - else - currentSeedHash = blockTemplate.SeedHash; - } - - break; - } - - case CryptonightHashType.Panthera: - { - // detect seed hash change - if(currentSeedHash != blockTemplate.SeedHash) - { - logger.Info(()=> $"Detected new seed hash {blockTemplate.SeedHash} starting @ height {blockTemplate.Height}"); - - if(poolConfig.EnableInternalStratum == true) - { - Panthera.WithLock(() => - { - // delete old seed - if(currentSeedHash != null) - Panthera.DeleteSeed(randomXRealm, currentSeedHash); - - // activate new one - currentSeedHash = blockTemplate.SeedHash; - Panthera.CreateSeed(randomXRealm, currentSeedHash, randomXFlagsOverride, randomXFlagsAdd, extraPoolConfig.RandomXVMCount); - }); - } - - else - currentSeedHash = blockTemplate.SeedHash; - } - - break; - } } } @@ -344,6 +260,23 @@ private async Task SubmitBlockAsync(Share share, string blobHex, string bl return true; } + public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out string target) + { + blob = null; + target = null; + + var job = currentJob; + + if(job != null) + job.PrepareWorkerJob(workerJob, out blob, out target); + } + + public override CryptonoteJob GetJobForStratum() + { + var job = currentJob; + return job; + } + #region API-Surface public IObservable Blocks { get; private set; } @@ -439,22 +372,6 @@ public bool ValidateAddress(string address) public BlockchainStats BlockchainStats { get; } = new(); - public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out string target) - { - blob = null; - target = null; - - var job = currentJob; - - if(job != null) - { - lock(job) - { - job.PrepareWorkerJob(workerJob, out blob, out target); - } - } - } - public async ValueTask SubmitShareAsync(StratumConnection worker, CryptonoteSubmitShareRequest request, CryptonoteWorkerJob workerJob, CancellationToken ct) { @@ -585,10 +502,6 @@ protected override async Task AreDaemonsConnectedAsync(CancellationToken c { var response = await rpc.ExecuteAsync(logger, CryptonoteCommands.GetInfo, ct); - // update stats - if(!string.IsNullOrEmpty(response?.Response.Version)) - BlockchainStats.NodeVersion = response?.Response.Version; - return response.Error == null && response.Response != null && (response.Response.OutgoingConnectionsCount + response.Response.IncomingConnectionsCount) > 0; } @@ -709,6 +622,25 @@ protected override async Task PostStartInitAsync(CancellationToken ct) .Concat() .Subscribe(); + if(poolConfig.EnableInternalStratum == true) + { + // make sure we have a current light cache + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(5)); + + do + { + var blockTemplate = await GetBlockTemplateAsync(ct); + + if(blockTemplate?.Response != null) + { + UpdateHashParams(blockTemplate.Response); + break; + } + + logger.Info(() => "Waiting for first valid block template"); + } while(await timer.WaitForNextTickAsync(ct)); + } + SetupJobUpdates(ct); } diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs index 13ed3f3494..6ca84a418f 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs @@ -52,7 +52,6 @@ public CryptonotePayoutHandler( private CryptonoteNetworkType? networkType; private CryptonotePoolPaymentProcessingConfigExtra extraConfig; private bool walletSupportsTransferSplit; - protected override string LogCategory => "Cryptonote Payout Handler"; @@ -201,6 +200,7 @@ private async Task PayoutBatch(Balance[] balances, CancellationToken ct) return false; TransferRequest request; + // not all Cryptonote coins are equal switch(coin.Symbol) { @@ -213,6 +213,7 @@ private async Task PayoutBatch(Balance[] balances, CancellationToken ct) .Select(x => { ExtractAddressAndPaymentId(x.Address, out var address, out _); + return new TransferDestination { Address = address, @@ -220,6 +221,7 @@ private async Task PayoutBatch(Balance[] balances, CancellationToken ct) AssetType = coin.Symbol }; }).ToArray(), + TransactionType = (uint) SalviumTransactionType.Transfer, SourceAsset = coin.Symbol, DestinationAsset = coin.Symbol, @@ -235,12 +237,14 @@ private async Task PayoutBatch(Balance[] balances, CancellationToken ct) .Select(x => { ExtractAddressAndPaymentId(x.Address, out var address, out _); + return new TransferDestination { Address = address, Amount = (ulong) Math.Floor(x.Amount * coin.SmallestUnit) }; }).ToArray(), + GetTxKey = true }; break; @@ -306,6 +310,7 @@ private async Task PayoutToPaymentId(Balance balance, CancellationToken ct return false; TransferRequest request; + // not all Cryptonote coins are equal switch(coin.Symbol) { @@ -322,6 +327,7 @@ private async Task PayoutToPaymentId(Balance balance, CancellationToken ct AssetType = coin.Symbol } }, + TransactionType = (uint) SalviumTransactionType.Transfer, PaymentId = paymentId, SourceAsset = coin.Symbol, @@ -341,6 +347,7 @@ private async Task PayoutToPaymentId(Balance balance, CancellationToken ct Amount = (ulong) Math.Floor(balance.Amount * coin.SmallestUnit) } }, + PaymentId = paymentId, GetTxKey = true }; @@ -467,8 +474,7 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, var blockHeader = rpcResult.Response.BlockHeader; // update progress - int PayoutMinBlockConfirmations = coin?.CoinbaseMinConfimations ?? CryptonoteConstants.PayoutMinBlockConfirmations; - block.ConfirmationProgress = Math.Min(1.0d, (double) blockHeader.Depth / PayoutMinBlockConfirmations); + block.ConfirmationProgress = Math.Min(1.0d, (double) blockHeader.Depth / CryptonoteConstants.PayoutMinBlockConfirmations); result.Add(block); messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); @@ -484,7 +490,7 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, } // matured and spendable? - if(blockHeader.Depth >= PayoutMinBlockConfirmations) + if(blockHeader.Depth >= CryptonoteConstants.PayoutMinBlockConfirmations) { block.Status = BlockStatus.Confirmed; block.ConfirmationProgress = 1; @@ -513,25 +519,6 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, block.Reward = (((blockHeader.Reward / coin.SmallestUnit) / (1m - reserveReward)) * miningReward) * coin.BlockrewardMultiplier; break; - - case "XEQ": - decimal EquilibriaMiningReward = EquilibriaConstants.EquilibriaMiningRewardInitial; - - block.Reward = (((blockHeader.Reward / coin.SmallestUnit)) * EquilibriaMiningReward) * coin.BlockrewardMultiplier; - break; - - case "MRL": - decimal MoreloReserveReward = MoreloConstants.MoreloReserveRewardInitial; - - block.Reward = (((blockHeader.Reward / coin.SmallestUnit)) - MoreloReserveReward) * coin.BlockrewardMultiplier; - break; - - case "GNTL": - decimal GntlMiningReward = GntlConstants.GntlMiningRewardInitial; - - block.Reward = (((blockHeader.Reward / coin.SmallestUnit)) * GntlMiningReward) * coin.BlockrewardMultiplier; - break; - default: block.Reward = (blockHeader.Reward / coin.SmallestUnit) * coin.BlockrewardMultiplier; break; @@ -553,10 +540,7 @@ public override async Task UpdateBlockRewardBalancesAsync(IDbConnection var blockRewardRemaining = await base.UpdateBlockRewardBalancesAsync(con, tx, pool, block, ct); // Deduct static reserve for tx fees - var coin = poolConfig.Template.As(); - var StaticTransactionFeeReserve = (coin.Symbol == "MRL") ? MoreloConstants.MoreloStaticTransactionFeeReserve : CryptonoteConstants.StaticTransactionFeeReserve; - - blockRewardRemaining -= StaticTransactionFeeReserve; + blockRewardRemaining -= CryptonoteConstants.StaticTransactionFeeReserve; return blockRewardRemaining; } @@ -658,10 +642,12 @@ public async Task PayoutAsync(IMiningPool pool, Balance[] balances, Cancellation await PayoutBatch(simpleBalances); #else { - var maxBatchSize = 15; // going over 15 yields "sv/gamma are too large" + var maxBatchSize = extraConfig?.MaximumDestinationPerTransfer ?? 15; // going over 15 yields "sv/gamma are too large" var pageSize = maxBatchSize; var pageCount = (int) Math.Ceiling((double) simpleBalances.Length / pageSize); + logger.Info(() => $"[{LogCategory}] Maximum of simultaneous destination address in a single transaction: {maxBatchSize}"); + for(var i = 0; i < pageCount; i++) { var page = simpleBalances diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs index 77fdfb06ee..47aab8f4ce 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs @@ -91,7 +91,6 @@ private async Task OnLoginAsync(StratumConnection connection, Timestamped $"[{connection.ConnectionId}] Nicehash detected. Using miner supplied difficulty of {staticDiff.Value}"); } - // Start diff - if(startDiff.HasValue) - { - if(context.VarDiff != null && startDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && startDiff.Value > context.Difficulty) - { - context.SetDifficulty(startDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {startDiff.Value}"); - } - else - { - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {context.VarDiff.Config.MinDiff}"); - } - } - - // Static diff - if(staticDiff.HasValue && !startDiff.HasValue) - { - if(context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty) - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(staticDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); - } - else - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {context.VarDiff.Config.MinDiff}"); - } - } + // Static diff + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) + { + context.VarDiff = null; // disable vardiff + context.SetDifficulty(staticDiff.Value); + + logger.Info(() => $"[{connection.ConnectionId}] Static difficulty set to {staticDiff.Value}"); + } // respond var loginResponse = new CryptonoteLoginResponse @@ -148,7 +126,18 @@ private async Task OnLoginAsync(StratumConnection connection, Timestamped(loginResponse, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // log association if(!string.IsNullOrEmpty(context.Worker)) @@ -186,9 +175,21 @@ private async Task OnGetJobAsync(StratumConnection connection, Timestamped(job, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + // respond + await connection.RespondAsync(response); } private CryptonoteJobParams CreateWorkerJob(StratumConnection connection) @@ -199,7 +200,7 @@ private CryptonoteJobParams CreateWorkerJob(StratumConnection connection) 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(target)) return null; var result = new CryptonoteJobParams @@ -217,7 +218,7 @@ private CryptonoteJobParams CreateWorkerJob(StratumConnection connection) // update context lock(context) { - context.AddJob(job); + context.AddJob(job, 4); } return result; @@ -233,6 +234,10 @@ private async Task OnSubmitAsync(StratumConnection connection, Timestamped(); // validate worker - if(connection.ConnectionId != submitRequest?.WorkerId || !context.IsAuthorized) - throw new StratumException(StratumError.MinusOne, "unauthorized"); + if(connection.ConnectionId != submitRequest?.WorkerId) + throw new StratumException(StratumError.MinusOne, "cheater"); // recognize activity context.LastActivity = clock.Now; @@ -258,7 +263,7 @@ private async Task OnSubmitAsync(StratumConnection connection, Timestamped(new CryptonoteResponseBase(), request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // publish messageBus.SendMessage(share); @@ -407,7 +424,19 @@ protected override async Task OnRequestAsync(StratumConnection connection, // For some reasons, we would never send a reply here :/ // But the official XMRig documentation is explicit, we should reply: https://xmrig.com/docs/extensions/keepalive // XMRig is such a gift, i wish more mining pool operators were like them and valued open-source, the same way the XMRig devs do - await connection.RespondAsync(new CryptonoteKeepAliveResponse(), request.Id); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(new CryptonoteKeepAliveResponse(), request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); break; default: diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteWorkerContext.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteWorkerContext.cs index 87684841e4..8370d1a5de 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteWorkerContext.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteWorkerContext.cs @@ -1,3 +1,6 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; using Miningcore.Mining; namespace Miningcore.Blockchain.Cryptonote; @@ -8,25 +11,29 @@ public class CryptonoteWorkerContext : WorkerContextBase /// Usually a wallet address /// NOTE: May include paymentid (seperated by a dot .) /// - public string Miner { get; set; } + public override string Miner { get; set; } /// /// Arbitrary worker identififer for miners using multiple rigs /// - public string Worker { get; set; } + public override string Worker { get; set; } - private List validJobs { get; } = new(); + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); - public void AddJob(CryptonoteWorkerJob job) + public virtual void AddJob(CryptonoteWorkerJob job, int maxActiveJobs) { - validJobs.Insert(0, job); + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); - while(validJobs.Count > 4) - validJobs.RemoveAt(validJobs.Count - 1); + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); } - public CryptonoteWorkerJob FindJob(string jobId) + public CryptonoteWorkerJob GetJob(string jobId) { - return validJobs.FirstOrDefault(x => x.Id == jobId); + return validJobs.ToArray().FirstOrDefault(x => x.Id == jobId); } } diff --git a/src/Miningcore/Blockchain/Cryptonote/DaemonRequests/TransferRequest.cs b/src/Miningcore/Blockchain/Cryptonote/DaemonRequests/TransferRequest.cs index 21b3a5ad05..66071a7485 100644 --- a/src/Miningcore/Blockchain/Cryptonote/DaemonRequests/TransferRequest.cs +++ b/src/Miningcore/Blockchain/Cryptonote/DaemonRequests/TransferRequest.cs @@ -33,7 +33,7 @@ public class TransferRequest /// Number of outputs to mix in the transaction (this output + N decoys from the blockchain) /// [JsonProperty("ring_size")] - public uint RingSize { get; set; } = 16; //XEQ Error: Requested ring size 7 too low, using 16 + public uint RingSize { get; set; } = 7; /// /// (Optional) Random 32-byte/64-character hex string to identify a transaction @@ -65,12 +65,14 @@ public class TransferRequest /// [JsonProperty("tx_type", NullValueHandling = NullValueHandling.Ignore)] public uint? TransactionType { get; set; } + // Salvium /// /// Define the type of coin to be sent /// [JsonProperty("source_asset", NullValueHandling = NullValueHandling.Ignore)] public string SourceAsset { get; set; } + // Salvium /// /// Define the type of coin to be received diff --git a/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/GetInfoResponse.cs b/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/GetInfoResponse.cs index 58174873a4..13cffd7a53 100644 --- a/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/GetInfoResponse.cs +++ b/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/GetInfoResponse.cs @@ -89,10 +89,4 @@ public class GetInfoResponse /// [JsonProperty("outgoing_connections_count")] public int OutgoingConnectionsCount { get; set; } - - /// - /// Version - /// - [JsonProperty("version")] - public string Version { get; set; } } diff --git a/src/Miningcore/Blockchain/Equihash/Custom/Veruscoin/VeruscoinJob.cs b/src/Miningcore/Blockchain/Equihash/Custom/Veruscoin/VeruscoinJob.cs index 25151516ef..a2e2317a23 100644 --- a/src/Miningcore/Blockchain/Equihash/Custom/Veruscoin/VeruscoinJob.cs +++ b/src/Miningcore/Blockchain/Equihash/Custom/Veruscoin/VeruscoinJob.cs @@ -232,7 +232,7 @@ protected override byte[] SerializeBlock(Span header, Span coinbase, protected override (Share Share, string BlockHex) ProcessShareInternal(StratumConnection worker, string nonce, uint nTime, string solution) { - var context = worker.ContextAs(); + var context = worker.ContextAs(); var solutionBytes = (Span) solution.HexToByteArray(); // serialize block-header @@ -477,7 +477,7 @@ public override (Share Share, string BlockHex) ProcessShare(StratumConnection wo Contract.Requires(!string.IsNullOrEmpty(nTime)); Contract.Requires(!string.IsNullOrEmpty(solution)); - var context = worker.ContextAs(); + var context = worker.ContextAs(); // validate nTime if(nTime.Length != 8) diff --git a/src/Miningcore/Blockchain/Equihash/EquihashConstants.cs b/src/Miningcore/Blockchain/Equihash/EquihashConstants.cs index eb7493b7d8..6ebc0a5ff5 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashConstants.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashConstants.cs @@ -13,7 +13,8 @@ public class EquihashConstants public class VeruscoinConstants { public const int SolutionSlice = 6; - public const string HashVersion2b2 = "2b2"; + public const string HashVersion2b2 = "2b2"; // PBaaS detection + public const string HashVersion2b2o = "2b2o"; public const string HashVersion2b1 = "2b1"; public const string HashVersion2b = "2b"; public const string HashVersion2 = "2"; diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJob.cs b/src/Miningcore/Blockchain/Equihash/EquihashJob.cs index 645f731423..fd65225e9f 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJob.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJob.cs @@ -355,7 +355,7 @@ protected virtual byte[] SerializeBlock(Span header, Span coinbase, protected virtual (Share Share, string BlockHex) ProcessShareInternal(StratumConnection worker, string nonce, uint nTime, string solution) { - var context = worker.ContextAs(); + var context = worker.ContextAs(); var solutionBytes = (Span) solution.HexToByteArray(); // serialize block-header @@ -567,7 +567,7 @@ public virtual (Share Share, string BlockHex) ProcessShare(StratumConnection wor Contract.Requires(!string.IsNullOrEmpty(nTime)); Contract.Requires(!string.IsNullOrEmpty(solution)); - var context = worker.ContextAs(); + var context = worker.ContextAs(); // validate nTime if(nTime.Length != 8) diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index 180ea1a3f1..b832159b86 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -136,15 +136,6 @@ await GetBlockTemplateAsync(ct) : job.Init(blockTemplate, NextJobId(), poolConfig, clusterConfig, clock, poolAddressDestination, network, solver); - lock(jobLock) - { - validJobs.Insert(0, job); - - // trim active jobs - while(validJobs.Count > maxActiveJobs) - validJobs.RemoveAt(validJobs.Count - 1); - } - if(isNew) { if(via != null) @@ -193,6 +184,12 @@ protected override object GetJobParamsForStratum(bool isNew) return job?.GetJobParams(isNew); } + public override EquihashJob GetJobForStratum() + { + var job = currentJob; + return job; + } + #region API-Surface public override void Configure(PoolConfig pc, ClusterConfig cc) @@ -227,7 +224,7 @@ public object[] GetSubscriberData(StratumConnection worker) { Contract.RequiresNonNull(worker); - var context = worker.ContextAs(); + var context = worker.ContextAs(); // assign unique ExtraNonce1 to worker (miner) context.ExtraNonce1 = extraNonceProvider.Next(); @@ -250,7 +247,7 @@ public async ValueTask SubmitShareAsync(StratumConnection worker, if(submission is not object[] submitParams) throw new StratumException(StratumError.Other, "invalid params"); - var context = worker.ContextAs(); + var context = worker.ContextAs(); // extract params var workerValue = (submitParams[0] as string)?.Trim(); @@ -267,9 +264,9 @@ public async ValueTask SubmitShareAsync(StratumConnection worker, EquihashJob job; - lock(jobLock) + lock(context) { - job = validJobs.FirstOrDefault(x => x.JobId == jobId); + job = context.GetJob(jobId); } if(job == null) diff --git a/src/Miningcore/Blockchain/Equihash/EquihashPool.cs b/src/Miningcore/Blockchain/Equihash/EquihashPool.cs index 8aa1db8993..cd4929d613 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashPool.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashPool.cs @@ -115,7 +115,7 @@ protected override async Task InitStatsAsync(CancellationToken ct) protected async Task OnSubscribeAsync(StratumConnection connection, Timestamped tsRequest) { var request = tsRequest.Value; - var context = connection.ContextAs(); + var context = connection.ContextAs(); if(request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); @@ -135,7 +135,7 @@ protected async Task OnSubscribeAsync(StratumConnection connection, Timestamped< // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] var response = new JsonRpcResponse(data, request.Id); - if(context.IsNicehash) + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) { response.Extra = new Dictionary(); response.Extra["error"] = null; @@ -154,7 +154,7 @@ protected async Task OnAuthorizeAsync(StratumConnection connection, Timestamped< if(request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); - var context = connection.ContextAs(); + var context = connection.ContextAs(); var requestParams = request.ParamsAs(); var workerValue = requestParams?.Length > 0 ? requestParams[0] : null; var password = requestParams?.Length > 1 ? requestParams[1] : null; @@ -177,7 +177,7 @@ protected async Task OnAuthorizeAsync(StratumConnection connection, Timestamped< // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] var response = new JsonRpcResponse(context.IsAuthorized, request.Id); - if(context.IsNicehash) + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) { response.Extra = new Dictionary(); response.Extra["error"] = null; @@ -191,7 +191,6 @@ protected async Task OnAuthorizeAsync(StratumConnection connection, Timestamped< // extract control vars from password var staticDiff = GetStaticDiffFromPassparts(passParts); - var startDiff = GetStartDiffFromPassparts(passParts); // Nicehash support var nicehashDiff = await GetNicehashStaticMinDiff(context, coin.Name, coin.GetAlgorithmName()); @@ -210,7 +209,9 @@ protected async Task OnAuthorizeAsync(StratumConnection connection, Timestamped< } // Static diff - if(staticDiff.HasValue && !startDiff.HasValue && (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty)) + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) { context.VarDiff = null; // disable vardiff context.SetDifficulty(staticDiff.Value); @@ -220,16 +221,11 @@ protected async Task OnAuthorizeAsync(StratumConnection connection, Timestamped< await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); } - // Start diff - if(startDiff.HasValue && (context.VarDiff != null && startDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && startDiff.Value > context.Difficulty)) - { - context.SetDifficulty(startDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {startDiff.Value}"); - } + var minerJobParams = CreateWorkerJob(connection, context.IsAuthorized); // send intial update await connection.NotifyAsync(EquihashStratumMethods.SetTarget, new object[] { EncodeTarget(context.Difficulty) }); - await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); } else @@ -248,10 +244,24 @@ protected async Task OnAuthorizeAsync(StratumConnection connection, Timestamped< } } + private object CreateWorkerJob(StratumConnection connection, bool cleanJob) + { + var context = connection.ContextAs(); + var job = manager.GetJobForStratum(); + + // update context + lock(context) + { + context.AddJob(job, manager.maxActiveJobs); + } + + return job.GetJobParams(cleanJob); + } + protected virtual async Task OnSubmitAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) { var request = tsRequest.Value; - var context = connection.ContextAs(); + var context = connection.ContextAs(); try { @@ -286,7 +296,7 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] var response = new JsonRpcResponse(true, request.Id); - if(context.IsNicehash) + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) { response.Extra = new Dictionary(); response.Extra["error"] = null; @@ -331,7 +341,7 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta private async Task OnSuggestTargetAsync(StratumConnection connection, Timestamped tsRequest) { var request = tsRequest.Value; - var context = connection.ContextAs(); + var context = connection.ContextAs(); if(request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); @@ -415,16 +425,30 @@ protected async Task OnNewJobAsync(object jobParams) logger.Info(() => $"Broadcasting job {((object[]) jobParams)[0]}"); + bool cleanJob; + switch(coin.Symbol) + { + case "VRSC": + + cleanJob = (bool) ((object[]) jobParams)[^2]; + break; + default: + + cleanJob = (bool) ((object[]) jobParams)[^1]; + break; + } + await Guard(() => ForEachMinerAsync(async (connection, ct) => { - var context = connection.ContextAs(); + var context = connection.ContextAs(); + var minerJobParams = CreateWorkerJob(connection, cleanJob); // varDiff: if the client has a pending difficulty change, apply it now if(context.ApplyPendingDifficulty()) await connection.NotifyAsync(EquihashStratumMethods.SetTarget, new object[] { EncodeTarget(context.Difficulty) }); // send job - await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); })); } @@ -445,14 +469,29 @@ protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, if(connection.Context.ApplyPendingDifficulty()) { + bool cleanJob; + switch(coin.Symbol) + { + case "VRSC": + + cleanJob = (bool) ((object[]) currentJobParams)[^2]; + break; + default: + + cleanJob = (bool) ((object[]) currentJobParams)[^1]; + break; + } + + var minerJobParams = CreateWorkerJob(connection, cleanJob); + await connection.NotifyAsync(EquihashStratumMethods.SetTarget, new object[] { EncodeTarget(connection.Context.Difficulty) }); - await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); } } protected override WorkerContextBase CreateWorkerContext() { - return new BitcoinWorkerContext(); + return new EquihashWorkerContext(); } private string EncodeTarget(double difficulty) diff --git a/src/Miningcore/Blockchain/Equihash/EquihashUtils.cs b/src/Miningcore/Blockchain/Equihash/EquihashUtils.cs index de073db115..5ddbbecdd7 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashUtils.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashUtils.cs @@ -8,7 +8,6 @@ public static class EquihashUtils { public static string EncodeTarget(double difficulty, EquihashCoinTemplate.EquihashNetworkParams chainConfig) { - string result; var diff = BigInteger.ValueOf((long) (difficulty * 255d)); var quotient = chainConfig.Diff1Value.Divide(diff).Multiply(BigInteger.ValueOf(255)); var bytes = quotient.ToByteArray().AsSpan(); @@ -17,14 +16,10 @@ public static string EncodeTarget(double difficulty, EquihashCoinTemplate.Equiha var padLength = EquihashConstants.TargetPaddingLength - bytes.Length; if(padLength > 0) - { bytes.CopyTo(padded.Slice(padLength, bytes.Length)); - result = padded.ToHexString(0, EquihashConstants.TargetPaddingLength); - } - else - result = bytes.ToHexString(0, EquihashConstants.TargetPaddingLength); + bytes.Slice(bytes.Length - padded.Length, padded.Length).CopyTo(padded); - return result; + return padded.ToHexString(); } } diff --git a/src/Miningcore/Blockchain/Equihash/EquihashWorkerContext.cs b/src/Miningcore/Blockchain/Equihash/EquihashWorkerContext.cs new file mode 100644 index 0000000000..297bb8ec24 --- /dev/null +++ b/src/Miningcore/Blockchain/Equihash/EquihashWorkerContext.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; +using Miningcore.Mining; + +namespace Miningcore.Blockchain.Equihash; + +public class EquihashWorkerContext : WorkerContextBase +{ + /// + /// Usually a wallet address + /// + public override string Miner { get; set; } + + /// + /// Arbitrary worker identififer for miners using multiple rigs + /// + public override string Worker { get; set; } + + /// + /// Unique value assigned per worker + /// + public string ExtraNonce1 { get; set; } + + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); + + public virtual void AddJob(EquihashJob job, int maxActiveJobs) + { + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); + + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); + } + + public EquihashJob GetJob(string jobId) + { + return validJobs.ToArray().FirstOrDefault(x => x.JobId == jobId); + } +} diff --git a/src/Miningcore/Blockchain/Ergo/ErgoJobManager.cs b/src/Miningcore/Blockchain/Ergo/ErgoJobManager.cs index 85909e76e2..862fd4af1a 100644 --- a/src/Miningcore/Blockchain/Ergo/ErgoJobManager.cs +++ b/src/Miningcore/Blockchain/Ergo/ErgoJobManager.cs @@ -36,7 +36,6 @@ public ErgoJobManager( private ErgoCoinTemplate coin; private ErgoClient rpc; private string network; - private readonly List validJobs = new(); private int maxActiveJobs = 4; private readonly int extraNonceSize; private readonly IExtraNonceProvider extraNonceProvider; @@ -115,15 +114,6 @@ await GetBlockTemplateAsync() : job.Init(blockTemplate, blockVersion, extraNonceSize, NextJobId()); - lock(jobLock) - { - validJobs.Insert(0, job); - - // trim active jobs - while(validJobs.Count > maxActiveJobs) - validJobs.RemoveAt(validJobs.Count - 1); - } - if(isNew) { if(via != null) @@ -232,6 +222,18 @@ await rpc.MiningSubmitSolutionAsync(new PowSolutions return false; } + private object[] GetJobParamsForStratum(bool isNew) + { + var job = currentJob; + return job?.GetJobParams(isNew); + } + + public override ErgoJob GetJobForStratum() + { + var job = currentJob; + return job; + } + #region API-Surface public IObservable Jobs { get; private set; } @@ -281,9 +283,9 @@ public async ValueTask SubmitShareAsync(StratumConnection worker, object ErgoJob job; - lock(jobLock) + lock(context) { - job = validJobs.FirstOrDefault(x => x.JobId == jobId); + job = context.GetJob(jobId); } if(job == null) @@ -461,11 +463,5 @@ protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) } while(await timer.WaitForNextTickAsync(ct)); } - private object[] GetJobParamsForStratum(bool isNew) - { - var job = currentJob; - return job?.GetJobParams(isNew); - } - #endregion // Overrides } diff --git a/src/Miningcore/Blockchain/Ergo/ErgoPool.cs b/src/Miningcore/Blockchain/Ergo/ErgoPool.cs index 1148cc47f7..8820138f84 100644 --- a/src/Miningcore/Blockchain/Ergo/ErgoPool.cs +++ b/src/Miningcore/Blockchain/Ergo/ErgoPool.cs @@ -66,7 +66,18 @@ protected virtual async Task OnSubscribeAsync(StratumConnection connection, Time .Concat(manager.GetSubscriberData(connection)) .ToArray(); - await connection.RespondAsync(data, request.Id); + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] + var response = new JsonRpcResponse(data, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // setup worker context context.IsSubscribed = true; @@ -98,15 +109,25 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time if(context.IsAuthorized) { + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] + var response = new JsonRpcResponse(context.IsAuthorized, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + // respond - await connection.RespondAsync(context.IsAuthorized, request.Id); + await connection.RespondAsync(response); // log association logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); // extract control vars from password var staticDiff = GetStaticDiffFromPassparts(passParts); - var startDiff = GetStartDiffFromPassparts(passParts); // Nicehash support var nicehashDiff = await GetNicehashStaticMinDiff(context, coin.Name, coin.GetAlgorithmName()); @@ -125,27 +146,20 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time } // Static diff - if(staticDiff.HasValue && !startDiff.HasValue && (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty)) + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) { context.VarDiff = null; // disable vardiff context.SetDifficulty(staticDiff.Value); logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); - - await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); } - // Start diff - if(startDiff.HasValue && (context.VarDiff != null && startDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && startDiff.Value > context.Difficulty)) - { - context.SetDifficulty(startDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {startDiff.Value}"); - - await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); - } + var minerJobParams = CreateWorkerJob(connection, context.IsAuthorized); // send intial update - await SendJob(connection, context, currentJobParams); + await SendJob(connection, context, minerJobParams); } else @@ -164,6 +178,21 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time } } + private object[] CreateWorkerJob(StratumConnection connection, bool cleanJob) + { + var context = connection.ContextAs(); + var maxActiveJobs = extraPoolConfig?.MaxActiveJobs ?? 4; + var job = manager.GetJobForStratum(); + + // update context + lock(context) + { + context.AddJob(job, maxActiveJobs); + } + + return job.GetJobParams(cleanJob); + } + protected virtual async Task OnSubmitAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) { var request = tsRequest.Value; @@ -196,7 +225,19 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta // submit var share = await manager.SubmitShareAsync(connection, requestParams, ct); - await connection.RespondAsync(true, request.Id); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] + var response = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // publish messageBus.SendMessage(share); @@ -241,8 +282,9 @@ protected virtual async Task OnNewJobAsync(object[] jobParams) await Guard(() => ForEachMinerAsync(async (connection, ct) => { var context = connection.ContextAs(); + var minerJobParams = CreateWorkerJob(connection, (bool) jobParams[^1]); - await SendJob(connection, context, currentJobParams); + await SendJob(connection, context, minerJobParams); })); } @@ -390,7 +432,9 @@ protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, if(context.ApplyPendingDifficulty()) { - await SendJob(connection, context, currentJobParams); + var minerJobParams = CreateWorkerJob(connection, (bool) currentJobParams[^1]); + + await SendJob(connection, context, minerJobParams); } } diff --git a/src/Miningcore/Blockchain/Ergo/ErgoWorkerContext.cs b/src/Miningcore/Blockchain/Ergo/ErgoWorkerContext.cs index 6d19d8f5a2..3ca826d1bf 100644 --- a/src/Miningcore/Blockchain/Ergo/ErgoWorkerContext.cs +++ b/src/Miningcore/Blockchain/Ergo/ErgoWorkerContext.cs @@ -1,3 +1,6 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; using Miningcore.Mining; namespace Miningcore.Blockchain.Ergo; @@ -7,15 +10,34 @@ public class ErgoWorkerContext : WorkerContextBase /// /// Usually a wallet address /// - public string Miner { get; set; } + public override string Miner { get; set; } /// /// Arbitrary worker identififer for miners using multiple rigs /// - public string Worker { get; set; } + public override string Worker { get; set; } /// /// Unique value assigned per worker /// public string ExtraNonce1 { get; set; } + + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); + + public virtual void AddJob(ErgoJob job, int maxActiveJobs) + { + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); + + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); + } + + public ErgoJob GetJob(string jobId) + { + return validJobs.ToArray().FirstOrDefault(x => x.JobId == jobId); + } } diff --git a/src/Miningcore/Blockchain/Ethereum/Configuration/EthereumPoolConfigExtra.cs b/src/Miningcore/Blockchain/Ethereum/Configuration/EthereumPoolConfigExtra.cs index 1670151755..39b2fd8157 100644 --- a/src/Miningcore/Blockchain/Ethereum/Configuration/EthereumPoolConfigExtra.cs +++ b/src/Miningcore/Blockchain/Ethereum/Configuration/EthereumPoolConfigExtra.cs @@ -19,10 +19,10 @@ public class EthereumPoolConfigExtra /// https://braiins.com/blog/hashrate-robbery-stratum-v2-fixes-this-and-more /// https://eips.ethereum.org/EIPS/eip-1571 /// https://github.com/AndreaLanfranchi/EthereumStratum-2.0.0/issues/10#issuecomment-595053258 - /// Based on that critical fact, mining pool should be cautious of the risks of using a such deprecated and broken stratum protocol. Used it at your own risks. + /// Based on that critical fact, mining pool should be cautious of the risks of using a such deprecated and broken stratum protocol. Use it at your own risks. /// "Ethash Stratum V1" protocol is disabled by default /// - public bool enableEthashStratumV1 { get; set; } = false; + public bool EnableEthashStratumV1 { get; set; } = false; /// /// getWork stream published via ZMQ diff --git a/src/Miningcore/Blockchain/Ethereum/Custom/Cortex/CortexJob.cs b/src/Miningcore/Blockchain/Ethereum/Custom/Cortex/CortexJob.cs new file mode 100644 index 0000000000..da5b26aacd --- /dev/null +++ b/src/Miningcore/Blockchain/Ethereum/Custom/Cortex/CortexJob.cs @@ -0,0 +1,155 @@ +using System; +using System.Globalization; +using System.Numerics; +using System.Reactive.Threading.Tasks; +using Miningcore.Crypto.Hashing.Algorithms; +using Miningcore.Crypto.Hashing.Ethash; +using Miningcore.Extensions; +using Miningcore.Native; +using Miningcore.Stratum; +using Miningcore.Util; +using NBitcoin; +using NLog; + +namespace Miningcore.Blockchain.Ethereum.Custom.Cortex; + +public class CortexJob : EthereumJob +{ + protected CortexCuckooCycle cortexCuckooCycleHasher; + protected Sha3_256 sha3Hasher; + protected Blake2b blake2bHasher; + + public CortexJob(string id, EthereumBlockTemplate blockTemplate, ILogger logger, IEthashLight ethash) : base(id, blockTemplate, logger, ethash) + { + this.cortexCuckooCycleHasher = new CortexCuckooCycle(); + this.sha3Hasher = new Sha3_256(); + this.blake2bHasher = new Blake2b(); + } + + protected virtual byte[] SerializeHeader(ulong nonce) + { + using(var stream = new MemoryStream(CortexConstants.CuckarooHeaderNonceSize)) + { + var bw = new BinaryWriter(stream); + + bw.Write(BlockTemplate.Header.HexToByteArray()); + bw.Write((BitConverter.IsLittleEndian ? BitConverter.GetBytes(nonce) : BitConverter.GetBytes(nonce).ReverseInPlace())); // cortex-cuckoo-cycles expects a little endian format. + + return stream.ToArray(); + } + } + + protected virtual uint[] SerializeSolution(string solution) + { + // allocate a uint array of size 42 + var solutionUints = new uint[CortexConstants.CuckarooSolutionSize]; + var solutionBytes = (Span) solution.HexToByteArray(); + + // fill the buffer with the big-endian representation of each uint in solution + for (int i = 0; i < solutionUints.Length; i++) + { + var slice = solutionBytes.Slice(i * 4, 4); + + solutionUints[i] = BitConverter.ToUInt32(slice); + } + + return solutionUints; + } + + protected virtual byte[] SerializeCoinbase(uint[] solution) + { + // allocate a byte array of size 42 * 4 + var solutionBytes = new byte[solution.Length * 4]; + + // fill the buffer with the big-endian representation of each uint in solution + for (int i = 0; i < solution.Length; i++) + { + var uintBytes = (!BitConverter.IsLittleEndian) ? BitConverter.GetBytes(solution[i]).ReverseInPlace() : BitConverter.GetBytes(solution[i]); // sha3_256 expects a big endian format. + + uintBytes.CopyTo(solutionBytes, i * 4); + } + + var coinbaseBytes = new byte[32]; + sha3Hasher.Digest(solutionBytes, coinbaseBytes); + + return coinbaseBytes; + } + + public override async Task ProcessShareAsync(StratumConnection worker, + string workerName, string fullNonceHex, string solution, CancellationToken ct) + { + // dupe check + lock(workerNonces) + { + RegisterNonce(worker, fullNonceHex); + } + + var context = worker.ContextAs(); + + if(!ulong.TryParse(fullNonceHex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var fullNonce)) + throw new StratumException(StratumError.MinusOne, "bad nonce " + fullNonceHex); + + var solutionBytes = SerializeSolution(solution); + + await Task.Run( () => + { + var headerBytes = SerializeHeader(fullNonce); + + if(cortexCuckooCycleHasher.Verify(headerBytes, solutionBytes) > 0) + throw new StratumException(StratumError.MinusOne, "bad hash"); + }, ct); + + var resultBytes = SerializeCoinbase(solutionBytes); + + // test if share meets at least workers current difficulty + resultBytes.ReverseInPlace(); + var resultValue = new uint256(resultBytes); + var resultValueBig = resultBytes.AsSpan().ToBigInteger(); + var shareDiff = (double) BigInteger.Divide(EthereumConstants.BigMaxValue, resultValueBig) / EthereumConstants.Pow2x32; + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; + var isBlockCandidate = resultValue <= blockTarget; + + 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) + { + ratio = shareDiff / context.PreviousDifficulty.Value; + + if(ratio < 0.99) + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + + // use previous difficulty + stratumDifficulty = context.PreviousDifficulty.Value; + } + + else + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + } + + var share = new Share + { + BlockHeight = (long) BlockTemplate.Height, + IpAddress = worker.RemoteEndpoint?.Address?.ToString(), + Miner = context.Miner, + Worker = workerName, + UserAgent = context.UserAgent, + IsBlockCandidate = isBlockCandidate, + Difficulty = stratumDifficulty * EthereumConstants.Pow2x32 + }; + + if(share.IsBlockCandidate) + { + fullNonceHex = "0x" + fullNonceHex; + var headerHash = BlockTemplate.Header; + var mixHash = resultBytes.ToHexString(true); + + share.TransactionConfirmationData = ""; + + return new SubmitResult(share, fullNonceHex, headerHash, mixHash); + } + + return new SubmitResult(share); + } +} diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs b/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs index b06fba52cc..4110692ecf 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs @@ -126,6 +126,22 @@ public class UbiqConstants public const decimal BaseRewardInitial = 8.0m; } +// CORTEX block reward distribution - +// https://github.com/CortexFoundation/CortexTheseus/blob/master/params/config.go#L88 +public class CortexConstants +{ + public static double Pow2x30 = Math.Pow(2, 30); + public static BigInteger BigPow2x30 = new(Pow2x30); + + public const ulong BaseBlockRewardPeriod = 8409600; // Halving every four years: 365 days * 24 hours * 60 minutes * 4 blocks * 4 years = 8409600 + public const ulong DoloresBlockRewardPeriod = 1000000; + + public const decimal BaseRewardInitial = 7.0m; + + public const int CuckarooHeaderNonceSize = 40; + public const int CuckarooSolutionSize = 42; +} + public enum EthereumNetworkType { Main = 1, @@ -140,6 +156,9 @@ public enum EthereumNetworkType OctaSpace = 800001, OctaSpaceTestnet = 800002, Hypra = 622277, + Cortex = 21, + Dolores = 43, + Bernard = 42, Unknown = -1, } @@ -158,28 +177,31 @@ public enum GethChainType OctaSpace, OctaSpaceTestnet, Hypra, + Cortex = 21, + Dolores = 43, + Bernard = 42, Unknown = -1, } public static class EthCommands { - public const string GetWork = "eth_getWork"; - public const string SubmitWork = "eth_submitWork"; - public const string Sign = "eth_sign"; + public const string GetWork = "_getWork"; + public const string SubmitWork = "_submitWork"; + public const string Sign = "_sign"; public const string GetNetVersion = "net_version"; public const string GetClientVersion = "web3_clientVersion"; - public const string GetCoinbase = "eth_coinbase"; - public const string GetAccounts = "eth_accounts"; + public const string GetCoinbase = "_coinbase"; + public const string GetAccounts = "_accounts"; public const string GetPeerCount = "net_peerCount"; - public const string GetSyncState = "eth_syncing"; - public const string GetBlockNumber = "eth_blockNumber"; - public const string GetBlockByNumber = "eth_getBlockByNumber"; - public const string GetBlockByHash = "eth_getBlockByHash"; - public const string GetUncleByBlockNumberAndIndex = "eth_getUncleByBlockNumberAndIndex"; - public const string GetTxReceipt = "eth_getTransactionReceipt"; - public const string SendTx = "eth_sendTransaction"; + public const string GetSyncState = "_syncing"; + public const string GetBlockNumber = "_blockNumber"; + public const string GetBlockByNumber = "_getBlockByNumber"; + public const string GetBlockByHash = "_getBlockByHash"; + public const string GetUncleByBlockNumberAndIndex = "_getUncleByBlockNumberAndIndex"; + public const string GetTxReceipt = "_getTransactionReceipt"; + public const string SendTx = "_sendTransaction"; public const string UnlockAccount = "personal_unlockAccount"; - public const string Subscribe = "eth_subscribe"; - public const string MaxPriorityFeePerGas = "eth_maxPriorityFeePerGas"; + public const string Subscribe = "_subscribe"; + public const string MaxPriorityFeePerGas = "_maxPriorityFeePerGas"; } diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs b/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs index 72564e1634..9f9b61dd9c 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs @@ -24,17 +24,17 @@ public EthereumJob(string id, EthereumBlockTemplate blockTemplate, ILogger logge blockTarget = new uint256(target.HexToReverseByteArray()); } - private readonly Dictionary> workerNonces = new(); + protected Dictionary> workerNonces = new(); public string Id { get; } public EthereumBlockTemplate BlockTemplate { get; } - private readonly uint256 blockTarget; - private readonly ILogger logger; - private readonly IEthashLight ethash; + protected uint256 blockTarget; + protected ILogger logger; + protected IEthashLight ethash; public record SubmitResult(Share Share, string FullNonceHex = null, string HeaderHash = null, string MixHash = null); - private void RegisterNonce(StratumConnection worker, string nonce) + protected void RegisterNonce(StratumConnection worker, string nonce) { var nonceLower = nonce.ToLower(); @@ -53,8 +53,8 @@ private void RegisterNonce(StratumConnection worker, string nonce) } } - public async Task ProcessShareAsync(StratumConnection worker, - string workerName, string fullNonceHex, CancellationToken ct) + public virtual async Task ProcessShareAsync(StratumConnection worker, + string workerName, string fullNonceHex, string solution, CancellationToken ct) { // dupe check lock(workerNonces) @@ -126,7 +126,7 @@ public async Task ProcessShareAsync(StratumConnection worker, return new SubmitResult(share); } - public object[] GetJobParamsForStratum() + public virtual object[] GetJobParamsForStratum() { return new object[] { @@ -137,7 +137,7 @@ public object[] GetJobParamsForStratum() }; } - public object[] GetWorkParamsForStratum(EthereumWorkerContext context) + public virtual object[] GetWorkParamsForStratum(EthereumWorkerContext context) { // https://github.com/edsonayllon/Stratum-Implementation-For-Pantheon var workerTarget = BigInteger.Divide(EthereumConstants.BigMaxValue, new BigInteger(context.Difficulty * EthereumConstants.Pow2x32)); diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs index 0c0a6647de..024a3ba5ed 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs @@ -6,8 +6,10 @@ using Autofac; using Miningcore.Blockchain.Bitcoin; using Miningcore.Blockchain.Ethereum.Configuration; +using Miningcore.Blockchain.Ethereum.Custom.Cortex; using Miningcore.Blockchain.Ethereum.DaemonResponses; using Miningcore.Configuration; +using Miningcore.Crypto.Hashing.Ethash; using Miningcore.Extensions; using Miningcore.JsonRpc; using Miningcore.Messaging; @@ -52,10 +54,19 @@ public EthereumJobManager( private GethChainType chainType; private readonly IMasterClock clock; private readonly IExtraNonceProvider extraNonceProvider; - private const int MaxBlockBacklog = 6; - protected readonly Dictionary validJobs = new(); private EthereumPoolConfigExtra extraPoolConfig; + private EthereumJob CreateJob(string jobId, EthereumBlockTemplate blockTemplate, ILogger logger, IEthashLight ethash) + { + switch(coin.Symbol) + { + case "CTXC": + return extraPoolConfig?.ChainTypeOverride == "Bernard" ? new EthereumJob(jobId, blockTemplate, logger, ethash) : new CortexJob(jobId, blockTemplate, logger, ethash); + } + + return new EthereumJob(jobId, blockTemplate, logger, ethash); + } + protected async Task UpdateJob(CancellationToken ct, string via = null) { try @@ -101,20 +112,7 @@ protected bool UpdateJob(EthereumBlockTemplate blockTemplate, string via = null) var jobId = NextJobId("x8"); // update template - job = new EthereumJob(jobId, blockTemplate, logger, coin.Ethash); - - lock(jobLock) - { - // add jobs - validJobs[jobId] = job; - - // remove old ones - var obsoleteKeys = validJobs.Keys - .Where(key => validJobs[key].BlockTemplate.Height < job.BlockTemplate.Height - MaxBlockBacklog).ToArray(); - - foreach(var key in obsoleteKeys) - validJobs.Remove(key); - } + job = CreateJob(jobId, blockTemplate, logger, coin.Ethash); currentJob = job; @@ -148,8 +146,8 @@ private async Task GetBlockTemplateAsync(CancellationToke { var requests = new[] { - new RpcRequest(EC.GetWork), - new RpcRequest(EC.GetBlockByNumber, new[] { (object) "latest", true }) + new RpcRequest(coin.RpcMethodPrefix + EC.GetWork), + new RpcRequest(coin.RpcMethodPrefix + EC.GetBlockByNumber, new[] { (object) "latest", true }) }; var responses = await rpc.ExecuteBatchAsync(logger, ct, requests); @@ -196,7 +194,7 @@ private async Task GetBlockTemplateAsync(CancellationToke private async Task ShowDaemonSyncProgressAsync(CancellationToken ct) { - var syncStateResponse = await rpc.ExecuteAsync(logger, EC.GetSyncState, ct); + var syncStateResponse = await rpc.ExecuteAsync(logger, coin.RpcMethodPrefix + EC.GetSyncState, ct); if(syncStateResponse.Error == null) { @@ -250,7 +248,7 @@ private async Task UpdateNetworkStatsAsync(CancellationToken ct) var requests = new[] { new RpcRequest(EC.GetPeerCount), - new RpcRequest(EC.GetBlockByNumber, new[] { (object) "latest", true }) + new RpcRequest(coin.RpcMethodPrefix + EC.GetBlockByNumber, new[] { (object) "latest", true }) }; var responses = await rpc.ExecuteBatchAsync(logger, ct, requests); @@ -274,7 +272,7 @@ private async Task UpdateNetworkStatsAsync(CancellationToken ct) var sampleSize = (ulong) 300; var sampleBlockNumber = latestBlockHeight - sampleSize; - var sampleBlockResults = await rpc.ExecuteAsync(logger, EC.GetBlockByNumber, ct, new[] { (object) sampleBlockNumber.ToStringHexWithPrefix(), true }); + var sampleBlockResults = await rpc.ExecuteAsync(logger, coin.RpcMethodPrefix + EC.GetBlockByNumber, ct, new[] { (object) sampleBlockNumber.ToStringHexWithPrefix(), true }); var sampleBlockTimestamp = sampleBlockResults.Response.Timestamp; var blockTime = (double) (latestBlockTimestamp - sampleBlockTimestamp) / sampleSize; @@ -293,7 +291,7 @@ private async Task UpdateNetworkStatsAsync(CancellationToken ct) private async Task SubmitBlockAsync(Share share, string fullNonceHex, string headerHash, string mixHash) { // submit work - var response = await rpc.ExecuteAsync(logger, EC.SubmitWork, CancellationToken.None, new[] + var response = await rpc.ExecuteAsync(logger, coin.RpcMethodPrefix + EC.SubmitWork, CancellationToken.None, new[] { fullNonceHex, headerHash, @@ -327,14 +325,20 @@ public object[] GetWorkParamsForStratum(EthereumWorkerContext context) return job?.GetWorkParamsForStratum(context) ?? Array.Empty(); } + public override EthereumJob GetJobForStratum() + { + var job = currentJob; + return job; + } + #region API-Surface public IObservable Jobs { get; private set; } public override void Configure(PoolConfig pc, ClusterConfig cc) { - extraPoolConfig = pc.Extra.SafeExtensionDataAs(); coin = pc.Template.As(); + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); // extract standard daemon endpoints daemonEndpoints = pc.Daemons @@ -389,19 +393,20 @@ public async Task SubmitShareV1Async(StratumConnection worker, string[] r var context = worker.ContextAs(); var nonce = request[0]; var header = request[1]; + var solution = request.Length > 2 ? request[2] : string.Empty; EthereumJob job; // stale? - lock(jobLock) + lock(context) { - job = validJobs.Values.FirstOrDefault(x => x.BlockTemplate.Header.Equals(header)); + job = context.validJobs.ToArray().FirstOrDefault(x => x.BlockTemplate.Header.Equals(header)); if(job == null) throw new StratumException(StratumError.MinusOne, "stale share"); } - return await SubmitShareAsync(worker, context, workerName, job, nonce.StripHexPrefix(), ct); + return await SubmitShareAsync(worker, context, workerName, job, nonce.StripHexPrefix(), solution, ct); } public async Task SubmitShareV2Async(StratumConnection worker, string[] request, CancellationToken ct) @@ -412,28 +417,29 @@ public async Task SubmitShareV2Async(StratumConnection worker, string[] r var context = worker.ContextAs(); var jobId = request[1]; var nonce = request[2]; + var solution = request.Length > 3 ? request[3] : string.Empty; EthereumJob job; // stale? - lock(jobLock) + lock(context) { // look up job by id - if(!validJobs.TryGetValue(jobId, out job)) + if((job = context.GetJob(jobId)) == null) throw new StratumException(StratumError.MinusOne, "stale share"); } // assemble full-nonce var fullNonceHex = context.ExtraNonce1 + nonce; - return await SubmitShareAsync(worker, context, context.Worker, job, fullNonceHex, ct); + return await SubmitShareAsync(worker, context, context.Worker, job, fullNonceHex, solution, ct); } private async Task SubmitShareAsync(StratumConnection worker, - EthereumWorkerContext context, string workerName, EthereumJob job, string nonce, CancellationToken ct) + EthereumWorkerContext context, string workerName, EthereumJob job, string nonce, string solution, CancellationToken ct) { // validate & process - var (share, fullNonceHex, headerHash, mixHash) = await job.ProcessShareAsync(worker, workerName, nonce, ct); + var (share, fullNonceHex, headerHash, mixHash) = await job.ProcessShareAsync(worker, workerName, nonce, solution, ct); share.PoolId = poolConfig.Id; share.NetworkDifficulty = BlockchainStats.NetworkDifficulty; @@ -473,7 +479,7 @@ protected override void ConfigureDaemons() protected override async Task AreDaemonsHealthyAsync(CancellationToken ct) { - var response = await rpc.ExecuteAsync(logger, EC.GetBlockByNumber, ct, new[] { (object) "latest", true }); + var response = await rpc.ExecuteAsync(logger, coin.RpcMethodPrefix + EC.GetBlockByNumber, ct, new[] { (object) "latest", true }); if(response.Error != null) { @@ -511,7 +517,7 @@ protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) do { - var syncStateResponse = await rpc.ExecuteAsync(logger, EC.GetSyncState, ct); + var syncStateResponse = await rpc.ExecuteAsync(logger, coin.RpcMethodPrefix + EC.GetSyncState, ct); var isSynched = syncStateResponse.Response is false; @@ -533,11 +539,13 @@ protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) protected override async Task PostStartInitAsync(CancellationToken ct) { + var coin = poolConfig.Template.As(); + var requests = new[] { new RpcRequest(EC.GetNetVersion), - new RpcRequest(EC.GetAccounts), - new RpcRequest(EC.GetCoinbase), + new RpcRequest(coin.RpcMethodPrefix + EC.GetAccounts), + new RpcRequest(coin.RpcMethodPrefix + EC.GetCoinbase), }; var responses = await rpc.ExecuteBatchAsync(logger, ct, requests); @@ -556,7 +564,6 @@ protected override async Task PostStartInitAsync(CancellationToken ct) // var accounts = responses[1].Response.ToObject(); // var coinbase = responses[2].Response.ToObject(); var gethChain = extraPoolConfig?.ChainTypeOverride ?? "Ethereum"; - var coin = poolConfig.Template.As(); EthereumUtils.DetectNetworkAndChain(netVersion, gethChain, out networkType, out chainType); @@ -585,18 +592,22 @@ protected override async Task PostStartInitAsync(CancellationToken ct) if(blockTemplate != null) { - if(!string.IsNullOrEmpty(extraPoolConfig?.DagDir)) - logger.Info(() => "Loading current DAG ..."); - else - logger.Info(() => "Loading current light cache ..."); - - await coin.Ethash.GetCacheAsync(logger, blockTemplate.Height, ct); - - if(!string.IsNullOrEmpty(extraPoolConfig?.DagDir)) - logger.Info(() => "Loaded current DAG"); - else - logger.Info(() => "Loaded current light cache"); - + // not all ethereum coins use DAG + if(extraPoolConfig?.ChainTypeOverride != "Cortex" && extraPoolConfig?.ChainTypeOverride != "Dolores") + { + if(!string.IsNullOrEmpty(extraPoolConfig?.DagDir)) + logger.Info(() => "Loading current DAG ..."); + else + logger.Info(() => "Loading current light cache ..."); + + await coin.Ethash.GetCacheAsync(logger, blockTemplate.Height, ct); + + if(!string.IsNullOrEmpty(extraPoolConfig?.DagDir)) + logger.Info(() => "Loaded current DAG"); + else + logger.Info(() => "Loaded current light cache"); + } + break; } @@ -643,7 +654,7 @@ protected virtual async Task SetupJobUpdates(CancellationToken ct) retry: // stream work updates - var getWorkObs = rpc.WebsocketSubscribe(logger, ct, wsEndpointConfig, EC.Subscribe, new[] { wsSubscription }) + var getWorkObs = rpc.WebsocketSubscribe(logger, ct, wsEndpointConfig, coin.RpcMethodPrefix + EC.Subscribe, new[] { wsSubscription }) .Publish() .RefCount(); diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs index 8156ca0fa7..48aabffe5c 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs @@ -53,6 +53,8 @@ public EthereumPayoutHandler( private EthereumPoolConfigExtra extraPoolConfig; private EthereumPoolPaymentProcessingConfigExtra extraConfig; + private EthereumCoinTemplate coin; + protected override string LogCategory => "Ethereum Payout Handler"; #region IPayoutHandler @@ -64,6 +66,8 @@ public async Task ConfigureAsync(ClusterConfig cc, PoolConfig pc, CancellationTo extraPoolConfig = pc.Extra.SafeExtensionDataAs(); extraConfig = pc.PaymentProcessing.Extra.SafeExtensionDataAs(); + coin = poolConfig.Template.As(); + logger = LogUtil.GetPoolScopedLogger(typeof(EthereumPayoutHandler), pc); // configure standard daemon @@ -84,7 +88,6 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, if(!enoughPeers) return blocks; - var coin = poolConfig.Template.As(); var pageSize = 100; var pageCount = (int) Math.Ceiling(blocks.Length / (double) pageSize); var blockCache = new Dictionary(); @@ -99,7 +102,7 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, .ToArray(); // get latest block - var latestBlockResponse = await rpcClient.ExecuteAsync(logger, EC.GetBlockByNumber, ct, new[] { (object) "latest", true }); + var latestBlockResponse = await rpcClient.ExecuteAsync(logger, coin.RpcMethodPrefix + EC.GetBlockByNumber, ct, new[] { (object) "latest", true }); var latestBlockHeight = latestBlockResponse.Response.Height.Value; // execute batch @@ -115,6 +118,8 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, result.Add(block); messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); + + uint totalDuplicateBlockBefore = 0; // is it block mined by us? if(string.Equals(blockInfo.Miner, poolConfig.Address, StringComparison.OrdinalIgnoreCase)) @@ -147,8 +152,28 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, { logger.Info(() => $"[{LogCategory}] Got {totalDuplicateBlock} `{block.Status}` blocks with the same blockHeight: {block.BlockHeight}"); - block.Reward = GetUncleReward(chainType, block.BlockHeight, block.BlockHeight); - block.Status = BlockStatus.Confirmed; + totalDuplicateBlockBefore = await cf.Run(con => blockRepo.GetPoolDuplicateBlockBeforeCountByPoolHeightNoTypeAndStatusAsync(con, poolConfig.Id, Convert.ToInt64(block.BlockHeight), new[] + { + BlockStatus.Confirmed, + BlockStatus.Orphaned, + BlockStatus.Pending + }, block.Created)); + + block.Reward = GetUncleReward(chainType, block.BlockHeight, block.BlockHeight, totalDuplicateBlockBefore, coin.MaxUncles); + + // There is a rare case-scenario where an Uncle has a block reward of zero + // We must handle it carefully otherwise payout will be stuck forever + if(block.Reward > 0) + { + block.Status = BlockStatus.Confirmed; + block.ConfirmationProgress = 1; + } + else + { + block.Status = BlockStatus.Orphaned; + block.Reward = 0; + } + block.ConfirmationProgress = 1; block.BlockHeight = (ulong) blockInfo.Height; block.Type = EthereumConstants.BlockTypeUncle; @@ -158,7 +183,7 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); } else { - var blockHashResponse = await rpcClient.ExecuteAsync(logger, EC.GetBlockByNumber, ct, + var blockHashResponse = await rpcClient.ExecuteAsync(logger, coin.RpcMethodPrefix + EC.GetBlockByNumber, ct, new[] { (object) block.BlockHeight.ToStringHexWithPrefix(), true }); var blockMiner = blockHashResponse.Response.Miner; @@ -217,7 +242,7 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, if(blockInfo2.Uncles.Length > 0) { // fetch all uncles in a single RPC batch request - var uncleBatch = blockInfo2.Uncles.Select((x, index) => new RpcRequest(EC.GetUncleByBlockNumberAndIndex, + var uncleBatch = blockInfo2.Uncles.Select((x, index) => new RpcRequest(coin.RpcMethodPrefix + EC.GetUncleByBlockNumberAndIndex, new[] { blockInfo2.Height.Value.ToStringHexWithPrefix(), index.ToStringHexWithPrefix() })) .ToArray(); @@ -233,9 +258,16 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, if(uncle != null) { + totalDuplicateBlockBefore = await cf.Run(con => blockRepo.GetPoolDuplicateBlockBeforeCountByPoolHeightNoTypeAndStatusAsync(con, poolConfig.Id, Convert.ToInt64(uncle.Height.Value), new[] + { + BlockStatus.Confirmed, + BlockStatus.Orphaned, + BlockStatus.Pending + }, block.Created)); + // mature? if(block.Reward == 0) - block.Reward = GetUncleReward(chainType, uncle.Height.Value, blockInfo2.Height.Value); + block.Reward = GetUncleReward(chainType, uncle.Height.Value, blockInfo2.Height.Value, totalDuplicateBlockBefore, coin.MaxUncles); if(latestBlockHeight - uncle.Height.Value >= EthereumConstants.MinConfimations) { @@ -254,7 +286,7 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, } block.Hash = uncle.Hash; - block.Reward = GetUncleReward(chainType, uncle.Height.Value, blockInfo2.Height.Value); + block.Reward = GetUncleReward(chainType, uncle.Height.Value, blockInfo2.Height.Value, totalDuplicateBlockBefore, coin.MaxUncles); block.BlockHeight = uncle.Height.Value; // There is a rare case-scenario where an Uncle has a block reward of zero @@ -351,7 +383,7 @@ private async Task EnsureDaemonsSynchedAsync(CancellationToken ct) // ensure we have enough peers var infoResponse = await rpcClient.ExecuteAsync(logger, EC.GetPeerCount, ct); - if((networkType == EthereumNetworkType.Main || extraPoolConfig?.ChainTypeOverride == "Classic" || extraPoolConfig?.ChainTypeOverride == "Mordor" || networkType == EthereumNetworkType.MainPow || extraPoolConfig?.ChainTypeOverride == "Ubiq" || extraPoolConfig?.ChainTypeOverride == "EtherOne" || extraPoolConfig?.ChainTypeOverride == "Pink" || extraPoolConfig?.ChainTypeOverride == "OctaSpace" || extraPoolConfig?.ChainTypeOverride == "OctaSpaceTestnet" || extraPoolConfig?.ChainTypeOverride == "Hypra") && + if((networkType == EthereumNetworkType.Main || extraPoolConfig?.ChainTypeOverride == "Classic" || extraPoolConfig?.ChainTypeOverride == "Mordor" || networkType == EthereumNetworkType.MainPow || extraPoolConfig?.ChainTypeOverride == "Ubiq" || extraPoolConfig?.ChainTypeOverride == "EtherOne" || extraPoolConfig?.ChainTypeOverride == "Pink" || extraPoolConfig?.ChainTypeOverride == "OctaSpace" || extraPoolConfig?.ChainTypeOverride == "OctaSpaceTestnet" || extraPoolConfig?.ChainTypeOverride == "Hypra" || extraPoolConfig?.ChainTypeOverride == "Cortex" || extraPoolConfig?.ChainTypeOverride == "Dolores" || extraPoolConfig?.ChainTypeOverride == "Bernard") && (infoResponse.Error != null || string.IsNullOrEmpty(infoResponse.Response) || infoResponse.Response.IntegralFromHex() < EthereumConstants.MinPayoutPeerCount)) { @@ -368,7 +400,7 @@ private async Task EnsureDaemonsSynchedAsync(CancellationToken ct) if(cacheMisses.Any()) { - var blockBatch = cacheMisses.Select(height => new RpcRequest(EC.GetBlockByNumber, + var blockBatch = cacheMisses.Select(height => new RpcRequest(coin.RpcMethodPrefix + EC.GetBlockByNumber, new[] { (object) height.ToStringHexWithPrefix(), @@ -469,7 +501,20 @@ internal static decimal GetBaseBlockReward(GethChainType chainType, ulong height return HypraConstants.GrayGlacierBlockReward; return HypraConstants.BaseRewardInitial; - + + case GethChainType.Cortex: + case GethChainType.Bernard: + if(height >= CortexConstants.BaseBlockRewardPeriod) + return CortexConstants.BaseRewardInitial / Math.Floor((decimal) height / CortexConstants.BaseBlockRewardPeriod); + + return CortexConstants.BaseRewardInitial; + + case GethChainType.Dolores: + if(height >= CortexConstants.DoloresBlockRewardPeriod) + return CortexConstants.BaseRewardInitial / Math.Floor((decimal) height / CortexConstants.DoloresBlockRewardPeriod); + + return CortexConstants.BaseRewardInitial; + default: throw new Exception("Unable to determine block reward: Unsupported chain type"); } @@ -478,7 +523,7 @@ internal static decimal GetBaseBlockReward(GethChainType chainType, ulong height private async Task GetTxRewardAsync(DaemonResponses.Block blockInfo, CancellationToken ct) { // fetch all tx receipts in a single RPC batch request - var batch = blockInfo.Transactions.Select(tx => new RpcRequest(EC.GetTxReceipt, new[] { tx.Hash })) + var batch = blockInfo.Transactions.Select(tx => new RpcRequest(coin.RpcMethodPrefix + EC.GetTxReceipt, new[] { tx.Hash })) .ToArray(); var results = await rpcClient.ExecuteBatchAsync(logger, ct, batch); @@ -496,7 +541,7 @@ private async Task GetTxRewardAsync(DaemonResponses.Block blockInfo, Ca return result; } - internal static decimal GetUncleReward(GethChainType chainType, ulong uheight, ulong height) + internal static decimal GetUncleReward(GethChainType chainType, ulong uheight, ulong height, uint totalDuplicateBlockBefore, int maxUncles) { var reward = GetBaseBlockReward(chainType, height); @@ -539,7 +584,10 @@ internal static decimal GetUncleReward(GethChainType chainType, ulong uheight, u break; } - + + if(totalDuplicateBlockBefore > maxUncles) + reward = 0m; + return reward; } @@ -584,14 +632,14 @@ private async Task PayoutAsync(Balance balance, CancellationToken ct) if(extraPoolConfig?.ChainTypeOverride == "Ethereum" || extraPoolConfig?.ChainTypeOverride == "Main" || (extraPoolConfig?.ChainTypeOverride == "Ubiq") || extraPoolConfig?.ChainTypeOverride == "MainPow" || extraPoolConfig?.ChainTypeOverride == "EtherOne" ) { - var maxPriorityFeePerGas = await rpcClient.ExecuteAsync(logger, EC.MaxPriorityFeePerGas, ct); + var maxPriorityFeePerGas = await rpcClient.ExecuteAsync(logger, coin.RpcMethodPrefix + EC.MaxPriorityFeePerGas, ct); logger.Debug(() => $"[{LogCategory}] MaxPriorityFeePerGas: {maxPriorityFeePerGas.Response.IntegralFromHex()} Wei"); if(extraPoolConfig?.ChainTypeOverride == "Ubiq") { // get latest block - var latestBlockResponse = await rpcClient.ExecuteAsync(logger, EC.GetBlockByNumber, ct, new[] { (object) "latest", true }); + var latestBlockResponse = await rpcClient.ExecuteAsync(logger, coin.RpcMethodPrefix + EC.GetBlockByNumber, ct, new[] { (object) "latest", true }); var latestBlockHeight = latestBlockResponse.Response.Height.Value; // EIP-1559 Transaction @@ -627,17 +675,17 @@ private async Task PayoutAsync(Balance balance, CancellationToken ct) Value = amount.ToString("x").TrimStart('0'), Gas = extraConfig.Gas }; - response = await rpcClient.ExecuteAsync(logger, EC.SendTx, ct, new[] { requestPink }); + response = await rpcClient.ExecuteAsync(logger, coin.RpcMethodPrefix + EC.SendTx, ct, new[] { requestPink }); } else { - response = await rpcClient.ExecuteAsync(logger, EC.SendTx, ct, new[] { request }); + response = await rpcClient.ExecuteAsync(logger, coin.RpcMethodPrefix + EC.SendTx, ct, new[] { request }); } if(response.Error != null) - throw new Exception($"{EC.SendTx} returned error: {response.Error.Message} code {response.Error.Code}"); + throw new Exception($"{coin.RpcMethodPrefix}{EC.SendTx} returned error: {response.Error.Message} code {response.Error.Code}"); if(string.IsNullOrEmpty(response.Response) || EthereumConstants.ZeroHashPattern.IsMatch(response.Response)) - throw new Exception($"{EC.SendTx} did not return a valid transaction hash"); + throw new Exception($"{coin.RpcMethodPrefix}{EC.SendTx} did not return a valid transaction hash"); var txHash = response.Response; logger.Info(() => $"[{LogCategory}] Payment transaction id: {txHash}"); diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs b/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs index a5abdaf9a1..2d3294339f 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs @@ -76,7 +76,7 @@ private async Task OnSubscribeAsync(StratumConnection connection, Timestamped(data, request.Id); - if(context.IsNicehash) + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) { response.Extra = new Dictionary(); response.Extra["error"] = null; @@ -108,8 +108,19 @@ private async Task OnAuthorizeAsync(StratumConnection connection, Timestamped(context.IsAuthorized, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + // respond - await connection.RespondAsync(context.IsAuthorized, request.Id); + await connection.RespondAsync(response); if(context.IsAuthorized) { @@ -118,7 +129,6 @@ private async Task OnAuthorizeAsync(StratumConnection connection, Timestamped $"[{connection.ConnectionId}] Nicehash detected. Using miner supplied difficulty of {staticDiff.Value}"); } - // Start diff - if(startDiff.HasValue) - { - if(context.VarDiff != null && startDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && startDiff.Value > context.Difficulty) - { - context.SetDifficulty(startDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {startDiff.Value}"); - } - else - { - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {context.VarDiff.Config.MinDiff}"); - } - } - - // Static diff - if(staticDiff.HasValue && !startDiff.HasValue) - { - if(context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty) - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(staticDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); - } - else - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {context.VarDiff.Config.MinDiff}"); - } - } + // Static diff + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) + { + context.VarDiff = null; // disable vardiff + context.SetDifficulty(staticDiff.Value); + + logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); + } + + var ethereumJob = CreateWorkerJob(connection); await connection.NotifyAsync(EthereumStratumMethods.SetDifficulty, new object[] { context.Difficulty }); - await connection.NotifyAsync(EthereumStratumMethods.MiningNotify, manager.GetJobParamsForStratum()); + await connection.NotifyAsync(EthereumStratumMethods.MiningNotify, ethereumJob.GetJobParamsForStratum()); logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); } @@ -187,6 +178,20 @@ private async Task OnAuthorizeAsync(StratumConnection connection, Timestamped(); + var job = manager.GetJobForStratum(); + + // update context + lock(context) + { + context.AddJob(job, 6); + } + + return job; + } + private async Task OnSubmitAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct, bool v1 = false) { var request = tsRequest.Value; @@ -230,7 +235,18 @@ private async Task OnSubmitAsync(StratumConnection connection, Timestamped(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // publish messageBus.SendMessage(share); @@ -266,14 +282,16 @@ private async Task OnSubmitAsync(StratumConnection connection, Timestamped(context.IsAuthorized, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + // respond - await connection.RespondAsync(context.IsAuthorized, request.Id); + await connection.RespondAsync(response); if(context.IsAuthorized) { @@ -319,7 +348,6 @@ private async Task OnSubmitLoginAsync(StratumConnection connection, Timestamped< // Nicehash support var nicehashDiff = await GetNicehashStaticMinDiff(context, coin.Name, coin.GetAlgorithmName()); - var startDiff = GetStartDiffFromPassparts(passParts); if(nicehashDiff.HasValue) { @@ -335,20 +363,14 @@ private async Task OnSubmitLoginAsync(StratumConnection connection, Timestamped< } // Static diff - if(staticDiff.HasValue && !startDiff.HasValue && (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty)) + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) { context.VarDiff = null; // disable vardiff context.SetDifficulty(staticDiff.Value); logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); - - } - - // Start diff - if(startDiff.HasValue && (context.VarDiff != null && startDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && startDiff.Value > context.Difficulty)) - { - context.SetDifficulty(startDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {startDiff.Value}"); } logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); @@ -380,10 +402,22 @@ private async Task OnGetWorkAsync(StratumConnection connection, Timestamped(parameters, requestId); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } // respond - await connection.RespondAsync(parameters, requestId); + await connection.RespondAsync(response); } #endregion // Protocol V1 handlers @@ -467,7 +501,7 @@ await Guard(() => ForEachMinerAsync(async (connection, ct) => break; case 2: - await SendJob(context, connection, currentJobParams); + await SendJob(context, connection); break; } })); @@ -512,7 +546,19 @@ protected override async Task OnRequestAsync(StratumConnection connection, EnsureProtocolVersion(context, 2); // Pretend to support it even though we actually do not. Some miners drop the connection upon receiving an error from this - await connection.RespondAsync(true, request.Id); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] + var responseSubscribe = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + responseSubscribe.Extra = new Dictionary(); + responseSubscribe.Extra["error"] = null; + } + + await connection.RespondAsync(responseSubscribe); break; // V1 Stratum methods @@ -521,14 +567,14 @@ protected override async Task OnRequestAsync(StratumConnection connection, // https://eips.ethereum.org/EIPS/eip-1571 // https://github.com/AndreaLanfranchi/EthereumStratum-2.0.0/issues/10#issuecomment-595053258 // Based on that critical fact, mining pool should be cautious of the risks of using a such deprecated and broken stratum protocol. Used it at your own risks. - case EthereumStratumMethods.SubmitLogin: + case var _ when request.Method == coin.RpcMethodPrefix + EthereumStratumMethods.SubmitLogin: context.ProtocolVersion = 1; // lock in protocol version await OnSubmitLoginAsync(connection, tsRequest); break; - case EthereumStratumMethods.GetWork: - if(!extraPoolConfig.enableEthashStratumV1) + case var _ when request.Method == coin.RpcMethodPrefix + EthereumStratumMethods.GetWork: + if(!extraPoolConfig.EnableEthashStratumV1) { logger.Info(() => $"[{connection.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); @@ -543,8 +589,8 @@ protected override async Task OnRequestAsync(StratumConnection connection, } break; - case EthereumStratumMethods.SubmitWork: - if(!extraPoolConfig.enableEthashStratumV1) + case var _ when request.Method == coin.RpcMethodPrefix + EthereumStratumMethods.SubmitWork: + if(!extraPoolConfig.EnableEthashStratumV1) { logger.Info(() => $"[{connection.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); @@ -559,8 +605,19 @@ protected override async Task OnRequestAsync(StratumConnection connection, } break; - case EthereumStratumMethods.SubmitHashrate: - await connection.RespondAsync(true, request.Id); + case var _ when request.Method == coin.RpcMethodPrefix + EthereumStratumMethods.SubmitHashrate: + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] + var responseSubmitHashrate = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + responseSubmitHashrate.Extra = new Dictionary(); + responseSubmitHashrate.Extra["error"] = null; + } + + await connection.RespondAsync(responseSubmitHashrate); break; default: @@ -602,7 +659,7 @@ protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, break; case 2: - await SendJob(context, connection, manager.GetJobParamsForStratum()); + await SendJob(context, connection); break; } } diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumStratumMethods.cs b/src/Miningcore/Blockchain/Ethereum/EthereumStratumMethods.cs index ed5d023e7e..33642f5c75 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumStratumMethods.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumStratumMethods.cs @@ -40,20 +40,20 @@ public static class EthereumStratumMethods /// /// Used to login & subscribe to work from a server, required before all other communication. /// - public const string SubmitLogin = "eth_submitLogin"; + public const string SubmitLogin = "_submitLogin"; /// /// Used to request work /// - public const string GetWork = "eth_getWork"; + public const string GetWork = "_getWork"; /// /// Used to submit work (shares) /// - public const string SubmitWork = "eth_submitWork"; + public const string SubmitWork = "_submitWork"; /// /// Ignored /// - public const string SubmitHashrate = "eth_submitHashrate"; + public const string SubmitHashrate = "_submitHashrate"; } diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumWorkerContext.cs b/src/Miningcore/Blockchain/Ethereum/EthereumWorkerContext.cs index 66c9bf751f..52c832d101 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumWorkerContext.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumWorkerContext.cs @@ -1,3 +1,6 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; using Miningcore.Mining; namespace Miningcore.Blockchain.Ethereum; @@ -7,12 +10,12 @@ public class EthereumWorkerContext : WorkerContextBase /// /// Usually a wallet address /// - public string Miner { get; set; } + public override string Miner { get; set; } /// /// Arbitrary worker identififer for miners using multiple rigs /// - public string Worker { get; set; } + public override string Worker { get; set; } /// /// Stratum protocol version @@ -23,4 +26,23 @@ public class EthereumWorkerContext : WorkerContextBase /// Unique value assigned per worker /// public string ExtraNonce1 { get; set; } + + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); + + public virtual void AddJob(EthereumJob job, int maxActiveJobs) + { + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); + + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); + } + + public EthereumJob GetJob(string jobId) + { + return validJobs.ToArray().FirstOrDefault(x => x.Id == jobId); + } } diff --git a/src/Miningcore/Blockchain/Handshake/HandshakeJob.cs b/src/Miningcore/Blockchain/Handshake/HandshakeJob.cs index 462be3b93e..78d39e3596 100644 --- a/src/Miningcore/Blockchain/Handshake/HandshakeJob.cs +++ b/src/Miningcore/Blockchain/Handshake/HandshakeJob.cs @@ -82,7 +82,7 @@ protected virtual void BuildMerkleBranches() transactionHashes.Add(transaction.TxId.HexToByteArray()); // build merkle-root - merkleRoot = merkleTree.CreateRoot(headerHasher, transactionHashes); + merkleRoot = merkleTree.CreateRoot(coin.MerkleTreeHasherValue, transactionHashes); } protected virtual void BuildWitnessBranches() @@ -95,7 +95,7 @@ protected virtual void BuildWitnessBranches() transactionHashes.Add(transaction.Hash.HexToByteArray()); // build witness-root - witnessRoot = merkleTree.CreateRoot(headerHasher, transactionHashes); + witnessRoot = merkleTree.CreateRoot(coin.MerkleTreeHasherValue, transactionHashes); } protected virtual void BuildCoinbase() @@ -131,7 +131,7 @@ protected virtual void BuildCoinbase() coinbaseInitialHex = coinbaseInitial.ToHexString(); Span coinbaseInitialBytes = stackalloc byte[32]; - headerHasher.Digest((Span) coinbaseInitial, coinbaseInitialBytes); + coinbaseHasher.Digest(coinbaseInitial, coinbaseInitialBytes); coinbaseMerkle = coinbaseInitialBytes.ToArray(); } @@ -150,14 +150,14 @@ protected virtual void BuildCoinbase() coinbaseFinalHex = coinbaseFinal.ToHexString(); Span coinbaseFinalBytes = stackalloc byte[32]; - headerHasher.Digest((Span) coinbaseFinal, coinbaseFinalBytes); + coinbaseHasher.Digest(coinbaseFinal, coinbaseFinalBytes); Span coinbaseMerklCoinbaseFinalBytes = stackalloc byte[coinbaseMerkle.Length + coinbaseFinalBytes.Length]; coinbaseMerkle.CopyTo(coinbaseMerklCoinbaseFinalBytes); coinbaseFinalBytes.CopyTo(coinbaseMerklCoinbaseFinalBytes[coinbaseMerkle.Length..]); Span coinbaseBytes = stackalloc byte[32]; - headerHasher.Digest(coinbaseMerklCoinbaseFinalBytes, coinbaseBytes); + coinbaseHasher.Digest(coinbaseMerklCoinbaseFinalBytes, coinbaseBytes); coinbaseWitness = coinbaseBytes.ToArray(); } @@ -537,7 +537,7 @@ protected virtual byte[] SerializeExtranonce(string extraNonce1, string extraNon protected virtual (Share Share, string BlockHex) ProcessShareInternal( StratumConnection worker, string extraNonce2, uint nTime, uint nonce) { - var context = worker.ContextAs(); + var context = worker.ContextAs(); var extraNonceBytes = SerializeExtranonce(context.ExtraNonce1, extraNonce2); var subHeaderBytes = SerializeSubHeader(extraNonceBytes); @@ -546,7 +546,7 @@ protected virtual (Share Share, string BlockHex) ProcessShareInternal( var shareBytes = SerializeShare(nonce, nTime, commitHashBytes); Span shareLeftBytes = stackalloc byte[64]; - headerHasher.Digest(shareBytes, shareLeftBytes); + blockHasher.Digest(shareBytes, shareLeftBytes); var rightPaddingBytes = (Span) PaddingPreviousBlockWithTreeRoot(8); Span shareRightPaddingBytes = stackalloc byte[shareBytes.Length + rightPaddingBytes.Length]; @@ -554,7 +554,7 @@ protected virtual (Share Share, string BlockHex) ProcessShareInternal( rightPaddingBytes.CopyTo(shareRightPaddingBytes[shareBytes.Length..]); Span shareRightBytes = stackalloc byte[32]; - coinbaseHasher.Digest(shareRightPaddingBytes, shareRightBytes); + coin.ShareHasherValue.Digest(shareRightPaddingBytes, shareRightBytes); var centerPaddingBytes = (Span) PaddingPreviousBlockWithTreeRoot(32); Span shareLeftCenterPaddingHeaderRighthBytes = stackalloc byte[shareLeftBytes.Length + centerPaddingBytes.Length + shareRightBytes.Length]; @@ -563,7 +563,7 @@ protected virtual (Share Share, string BlockHex) ProcessShareInternal( shareRightBytes.CopyTo(shareLeftCenterPaddingHeaderRighthBytes[(shareLeftBytes.Length + centerPaddingBytes.Length)..]); Span shareHashBytes = stackalloc byte[32]; - headerHasher.Digest(shareLeftCenterPaddingHeaderRighthBytes, shareHashBytes); + blockHasher.Digest(shareLeftCenterPaddingHeaderRighthBytes, shareHashBytes); for (int i = 0; i < maskBytes.Length; i++) shareHashBytes[i] ^= maskBytes[i]; @@ -767,7 +767,7 @@ public virtual (Share Share, string BlockHex) ProcessShare(StratumConnection wor Contract.Requires(!string.IsNullOrEmpty(nTime)); Contract.Requires(!string.IsNullOrEmpty(nonce)); - var context = worker.ContextAs(); + var context = worker.ContextAs(); // validate nTime if(nTime.Length != 8) diff --git a/src/Miningcore/Blockchain/Handshake/HandshakeJobManager.cs b/src/Miningcore/Blockchain/Handshake/HandshakeJobManager.cs index 65e95e22b6..6ffb0242ae 100644 --- a/src/Miningcore/Blockchain/Handshake/HandshakeJobManager.cs +++ b/src/Miningcore/Blockchain/Handshake/HandshakeJobManager.cs @@ -94,15 +94,6 @@ await GetBlockTemplateAsync(ct) : ShareMultiplier, coin.CoinbaseHasherValue, coin.HeaderHasherValue, !isPoS ? coin.BlockHasherValue : coin.PoSBlockHasherValue ?? coin.BlockHasherValue); - lock(jobLock) - { - validJobs.Insert(0, job); - - // trim active jobs - while(validJobs.Count > maxActiveJobs) - validJobs.RemoveAt(validJobs.Count - 1); - } - if(isNew) { if(via != null) @@ -151,6 +142,12 @@ protected override object GetJobParamsForStratum(bool isNew) return job?.GetJobParams(); } + public override HandshakeJob GetJobForStratum() + { + var job = currentJob; + return job; + } + protected override void ConfigureDaemons() { if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) @@ -184,7 +181,7 @@ public object[] GetSubscriberData(StratumConnection worker) { Contract.RequiresNonNull(worker); - var context = worker.ContextAs(); + var context = worker.ContextAs(); // assign unique ExtraNonce1 to worker (miner) context.ExtraNonce1 = extraNonceProvider.Next(); @@ -208,7 +205,7 @@ public virtual async ValueTask SubmitShareAsync(StratumConnection worker, if(submission is not object[] submitParams) throw new StratumException(StratumError.Other, "invalid params"); - var context = worker.ContextAs(); + var context = worker.ContextAs(); // extract params var workerValue = (submitParams[0] as string)?.Trim(); @@ -222,9 +219,9 @@ public virtual async ValueTask SubmitShareAsync(StratumConnection worker, HandshakeJob job; - lock(jobLock) + lock(context) { - job = validJobs.FirstOrDefault(x => x.JobId == jobId); + job = context.GetJob(jobId); } if(job == null) @@ -281,6 +278,8 @@ public virtual object[] GetTransactions(StratumConnection worker, object submiss if(submission is not object[] submitParams) throw new StratumException(StratumError.Other, "invalid params"); + var context = worker.ContextAs(); + // extract params var jobId = submitParams[0] as string; @@ -289,9 +288,9 @@ public virtual object[] GetTransactions(StratumConnection worker, object submiss HandshakeJob job; - lock(jobLock) + lock(context) { - job = validJobs.FirstOrDefault(x => x.JobId == jobId); + job = context.GetJob(jobId); } if(job == null) diff --git a/src/Miningcore/Blockchain/Handshake/HandshakePool.cs b/src/Miningcore/Blockchain/Handshake/HandshakePool.cs index c0d3bfeb8b..a91b5cde20 100644 --- a/src/Miningcore/Blockchain/Handshake/HandshakePool.cs +++ b/src/Miningcore/Blockchain/Handshake/HandshakePool.cs @@ -49,7 +49,7 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time if(request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); - var context = connection.ContextAs(); + var context = connection.ContextAs(); var requestParams = request.ParamsAs(); if(requestParams?.Length < 1) @@ -71,34 +71,35 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time if(context.IsAuthorized) { + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] + var response = new JsonRpcResponse(context.IsAuthorized, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + // respond - await connection.RespondAsync(context.IsAuthorized, request.Id); + await connection.RespondAsync(response); // log association logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); // extract control vars from password var staticDiff = GetStaticDiffFromPassparts(passParts); - var startDiff = GetStartDiffFromPassparts(passParts); // Static diff - if(staticDiff.HasValue && !startDiff.HasValue && (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty)) + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) { context.VarDiff = null; // disable vardiff context.SetDifficulty(staticDiff.Value); logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); - - await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); - } - - // Start diff - if(startDiff.HasValue && (context.VarDiff != null && startDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && startDiff.Value > context.Difficulty)) - { - context.SetDifficulty(startDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {startDiff.Value}"); - - await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); } } @@ -125,7 +126,7 @@ protected virtual async Task OnSubscribeAsync(StratumConnection connection, Time if(request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); - var context = connection.ContextAs(); + var context = connection.ContextAs(); var requestParams = request.ParamsAs(); @@ -146,7 +147,18 @@ protected virtual async Task OnSubscribeAsync(StratumConnection connection, Time .Concat(subscriberData) .ToArray(); - await connection.RespondAsync(data, request.Id); + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] + var response = new JsonRpcResponse(data, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // setup worker context context.IsSubscribed = true; @@ -163,15 +175,31 @@ protected virtual async Task OnSubscribeAsync(StratumConnection connection, Time context.SetDifficulty(nicehashDiff.Value); } + var minerJobParams = CreateWorkerJob(connection, context.IsSubscribed); + // send intial update await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); - await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); + } + + private object CreateWorkerJob(StratumConnection connection, bool cleanJob) + { + var context = connection.ContextAs(); + var job = manager.GetJobForStratum(); + + // update context + lock(context) + { + context.AddJob(job, manager.maxActiveJobs); + } + + return job.GetJobParams(); } protected virtual async Task OnSubmitAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) { var request = tsRequest.Value; - var context = connection.ContextAs(); + var context = connection.ContextAs(); try { @@ -200,7 +228,19 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta // submit var share = await manager.SubmitShareAsync(connection, requestParams, ct); - await connection.RespondAsync(true, request.Id); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] + var response = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // publish messageBus.SendMessage(share); @@ -239,7 +279,7 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta protected virtual async Task OnGetTransactionsAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) { var request = tsRequest.Value; - var context = connection.ContextAs(); + var context = connection.ContextAs(); try { @@ -259,7 +299,19 @@ protected virtual async Task OnGetTransactionsAsync(StratumConnection connection // get transactions var transactions = manager.GetTransactions(connection, requestParams); - await connection.RespondAsync(transactions, request.Id); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] + var response = new JsonRpcResponse(transactions, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); } catch(StratumException ex) @@ -278,14 +330,15 @@ protected virtual async Task OnNewJobAsync(object jobParams) await Guard(() => ForEachMinerAsync(async (connection, ct) => { - var context = connection.ContextAs(); + var context = connection.ContextAs(); + var minerJobParams = CreateWorkerJob(connection, true); // varDiff: if the client has a pending difficulty change, apply it now if(context.ApplyPendingDifficulty()) await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); // send job - await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); })); } @@ -352,7 +405,7 @@ protected override async Task InitStatsAsync(CancellationToken ct) protected override WorkerContextBase CreateWorkerContext() { - return new BitcoinWorkerContext(); + return new HandshakeWorkerContext(); } protected override async Task OnRequestAsync(StratumConnection connection, @@ -400,8 +453,10 @@ protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, if(connection.Context.ApplyPendingDifficulty()) { + var minerJobParams = CreateWorkerJob(connection, true); + await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { connection.Context.Difficulty }); - await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); } } diff --git a/src/Miningcore/Blockchain/Handshake/HandshakeWorkerContext.cs b/src/Miningcore/Blockchain/Handshake/HandshakeWorkerContext.cs new file mode 100644 index 0000000000..76eec24ebe --- /dev/null +++ b/src/Miningcore/Blockchain/Handshake/HandshakeWorkerContext.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; +using Miningcore.Mining; + +namespace Miningcore.Blockchain.Handshake; + +public class HandshakeWorkerContext : WorkerContextBase +{ + /// + /// Usually a wallet address + /// + public override string Miner { get; set; } + + /// + /// Arbitrary worker identififer for miners using multiple rigs + /// + public override string Worker { get; set; } + + /// + /// Unique value assigned per worker + /// + public string ExtraNonce1 { get; set; } + + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); + + public virtual void AddJob(HandshakeJob job, int maxActiveJobs) + { + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); + + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); + } + + public HandshakeJob GetJob(string jobId) + { + return validJobs.ToArray().FirstOrDefault(x => x.JobId == jobId); + } +} diff --git a/src/Miningcore/Blockchain/JobManagerBase.cs b/src/Miningcore/Blockchain/JobManagerBase.cs index df60446601..926eb994aa 100644 --- a/src/Miningcore/Blockchain/JobManagerBase.cs +++ b/src/Miningcore/Blockchain/JobManagerBase.cs @@ -86,6 +86,7 @@ protected void OnBlockFound() protected abstract Task AreDaemonsConnectedAsync(CancellationToken ct); protected abstract Task EnsureDaemonsSynchedAsync(CancellationToken ct); protected abstract Task PostStartInitAsync(CancellationToken ct); + public abstract TJob GetJobForStratum(); #region API-Surface diff --git a/src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPaymentProcessingConfigExtra.cs b/src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPaymentProcessingConfigExtra.cs index 280e4b2547..9037a11735 100644 --- a/src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPaymentProcessingConfigExtra.cs +++ b/src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPaymentProcessingConfigExtra.cs @@ -9,13 +9,19 @@ public class KaspaPaymentProcessingConfigExtra /// /// Minimum block confirmations - /// Default: 10 + /// KAS minimum confirmation can change over time so please always study all those different changes very wisely: https://github.com/kaspanet/rusty-kaspa/blob/master/wallet/core/src/utxo/settings.rs + /// Default: (mainnet: 120, testnet: 110) /// public int? MinimumConfirmations { get; set; } - + + /// + /// kaspawallet daemon version which enables MaxFee (KASPA: "v0.12.18-rc5") + /// + public string VersionEnablingMaxFee { get; set; } + /// - /// Maximum number of payouts which can be done in parallel - /// Default: 2 + /// Maximum amount you're willing to pay (in SOMPI) + /// Default: 20000 (0.0002 KAS) /// - public int? MaxDegreeOfParallelPayouts { get; set; } + public ulong? MaxFee { get; set; } } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPoolConfigExtra.cs b/src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPoolConfigExtra.cs index 5a10cf2072..508ba72eb2 100644 --- a/src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPoolConfigExtra.cs +++ b/src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPoolConfigExtra.cs @@ -4,6 +4,12 @@ namespace Miningcore.Blockchain.Kaspa.Configuration; public class KaspaPoolConfigExtra { + /// + /// There are several reports of IDIOTS mining with ridiculous amount of hashrate and maliciously using a very low staticDiff in order to attack mining pools. + /// StaticDiff is now disabled by default for the KASPA family. Use it at your own risks. + /// + public bool EnableStaticDifficulty { get; set; } = false; + /// /// Maximum number of tracked jobs. /// Default: 8 @@ -12,7 +18,7 @@ public class KaspaPoolConfigExtra /// /// Arbitrary string added in the Kaspa coinbase tx - /// Default: "Miningcore" + /// Default: "Miningcore.developers["Cedric CRISPIN"]" /// public string ExtraData { get; set; } diff --git a/src/Miningcore/Blockchain/Kaspa/Custom/Astrix/AstrixJob.cs b/src/Miningcore/Blockchain/Kaspa/Custom/Astrix/AstrixJob.cs new file mode 100644 index 0000000000..b2cc051a9d --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/Custom/Astrix/AstrixJob.cs @@ -0,0 +1,92 @@ +using System; +using System.Numerics; +using Miningcore.Crypto; +using Miningcore.Crypto.Hashing.Algorithms; +using Miningcore.Extensions; +using Miningcore.Stratum; +using Miningcore.Util; +using NBitcoin; + +namespace Miningcore.Blockchain.Kaspa.Custom.Astrix; + +public class AstrixJob : KaspaJob +{ + protected Blake3 blake3Hasher; + protected Sha3_256 sha3_256Hasher; + + public AstrixJob(IHashAlgorithm customBlockHeaderHasher, IHashAlgorithm customCoinbaseHasher, IHashAlgorithm customShareHasher) : base(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher) + { + this.blake3Hasher = new Blake3(); + this.sha3_256Hasher = new Sha3_256(); + } + + protected override Share ProcessShareInternal(StratumConnection worker, string nonce) + { + var context = worker.ContextAs(); + + BlockTemplate.Header.Nonce = Convert.ToUInt64(nonce, 16); + + var prePowHashBytes = SerializeHeader(BlockTemplate.Header, true); + var coinbaseBytes = SerializeCoinbase(prePowHashBytes, BlockTemplate.Header.Timestamp, BlockTemplate.Header.Nonce); + + Span blake3Bytes = stackalloc byte[32]; + blake3Hasher.Digest(coinbaseBytes, blake3Bytes); + + Span sha3_256Bytes = stackalloc byte[32]; + sha3_256Hasher.Digest(blake3Bytes, sha3_256Bytes); + + Span hashCoinbaseBytes = stackalloc byte[32]; + shareHasher.Digest(ComputeCoinbase(prePowHashBytes, sha3_256Bytes), hashCoinbaseBytes); + + var targetHashCoinbaseBytes = new Target(new BigInteger(hashCoinbaseBytes.ToNewReverseArray(), true, true)); + var hashCoinbaseBytesValue = targetHashCoinbaseBytes.ToUInt256(); + //throw new StratumException(StratumError.LowDifficultyShare, $"nonce: {nonce} ||| hashCoinbaseBytes: {hashCoinbaseBytes.ToHexString()} ||| BigInteger: {targetHashCoinbaseBytes.ToBigInteger()} ||| Target: {hashCoinbaseBytesValue} - [stratum: {KaspaUtils.DifficultyToTarget(context.Difficulty)} - blockTemplate: {blockTargetValue}] ||| BigToCompact: {KaspaUtils.BigToCompact(targetHashCoinbaseBytes.ToBigInteger())} - [stratum: {KaspaUtils.BigToCompact(KaspaUtils.DifficultyToTarget(context.Difficulty))} - blockTemplate: {BlockTemplate.Header.Bits}] ||| shareDiff: {(double) new BigRational(KaspaConstants.Diff1b, targetHashCoinbaseBytes.ToBigInteger()) * shareMultiplier} - [stratum: {context.Difficulty} - blockTemplate: {KaspaUtils.TargetToDifficulty(KaspaUtils.CompactToBig(BlockTemplate.Header.Bits)) * (double) KaspaConstants.MinHash}]"); + + // calc share-diff + var shareDiff = (double) new BigRational(KaspaConstants.Diff1b, targetHashCoinbaseBytes.ToBigInteger()) * shareMultiplier; + + // diff check + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; + + // check if the share meets the much harder block difficulty (block candidate) + var isBlockCandidate = hashCoinbaseBytesValue <= blockTargetValue; + //var isBlockCandidate = true; + + // test if share meets at least workers current difficulty + 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) + { + ratio = shareDiff / context.PreviousDifficulty.Value; + + if(ratio < 0.99) + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + + // use previous difficulty + stratumDifficulty = context.PreviousDifficulty.Value; + } + + else + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + } + + var result = new Share + { + BlockHeight = (long) BlockTemplate.Header.DaaScore, + NetworkDifficulty = Difficulty, + Difficulty = context.Difficulty / shareMultiplier + }; + + if(isBlockCandidate) + { + var hashBytes = SerializeHeader(BlockTemplate.Header, false); + + result.IsBlockCandidate = true; + result.BlockHash = hashBytes.ToHexString(); + } + + return result; + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/Custom/Karlsencoin/KarlsencoinJob.cs b/src/Miningcore/Blockchain/Kaspa/Custom/Karlsencoin/KarlsencoinJob.cs index 8ec5432e55..21c059d400 100644 --- a/src/Miningcore/Blockchain/Kaspa/Custom/Karlsencoin/KarlsencoinJob.cs +++ b/src/Miningcore/Blockchain/Kaspa/Custom/Karlsencoin/KarlsencoinJob.cs @@ -1,6 +1,11 @@ -using Miningcore.Contracts; +using System; +using System.Numerics; using Miningcore.Crypto; using Miningcore.Crypto.Hashing.Algorithms; +using Miningcore.Extensions; +using Miningcore.Stratum; +using Miningcore.Util; +using NBitcoin; namespace Miningcore.Blockchain.Kaspa.Custom.Karlsencoin; @@ -9,4 +14,92 @@ public class KarlsencoinJob : KaspaJob public KarlsencoinJob(IHashAlgorithm customBlockHeaderHasher, IHashAlgorithm customCoinbaseHasher, IHashAlgorithm customShareHasher) : base(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher) { } + + protected override Span SerializeCoinbase(Span prePowHash, long timestamp, ulong nonce) + { + using(var stream = new MemoryStream()) + { + stream.Write(prePowHash); + stream.Write(BitConverter.GetBytes((ulong) timestamp)); + stream.Write(new byte[32]); // 32 zero bytes padding + stream.Write(BitConverter.GetBytes(nonce)); + + if(shareHasher is not FishHashKarlsen) + { + Span hashBytes = stackalloc byte[32]; + coinbaseHasher.Digest(stream.ToArray(), hashBytes); + + return (Span) hashBytes.ToArray(); + } + else + return (Span) stream.ToArray(); + } + } + + protected override Share ProcessShareInternal(StratumConnection worker, string nonce) + { + var context = worker.ContextAs(); + + BlockTemplate.Header.Nonce = Convert.ToUInt64(nonce, 16); + + var prePowHashBytes = SerializeHeader(BlockTemplate.Header, true); + var coinbaseBytes = SerializeCoinbase(prePowHashBytes, BlockTemplate.Header.Timestamp, BlockTemplate.Header.Nonce); + Span hashCoinbaseBytes = stackalloc byte[32]; + + if(shareHasher is not FishHashKarlsen) + shareHasher.Digest(ComputeCoinbase(prePowHashBytes, coinbaseBytes), hashCoinbaseBytes); + else + shareHasher.Digest(coinbaseBytes, hashCoinbaseBytes); + + var targetHashCoinbaseBytes = new Target(new BigInteger(hashCoinbaseBytes.ToNewReverseArray(), true, true)); + var hashCoinbaseBytesValue = targetHashCoinbaseBytes.ToUInt256(); + //throw new StratumException(StratumError.LowDifficultyShare, $"nonce: {nonce} ||| hashCoinbaseBytes: {hashCoinbaseBytes.ToHexString()} ||| BigInteger: {targetHashCoinbaseBytes.ToBigInteger()} ||| Target: {hashCoinbaseBytesValue} - [stratum: {KaspaUtils.DifficultyToTarget(context.Difficulty)} - blockTemplate: {blockTargetValue}] ||| BigToCompact: {KaspaUtils.BigToCompact(targetHashCoinbaseBytes.ToBigInteger())} - [stratum: {KaspaUtils.BigToCompact(KaspaUtils.DifficultyToTarget(context.Difficulty))} - blockTemplate: {BlockTemplate.Header.Bits}] ||| shareDiff: {(double) new BigRational(KaspaConstants.Diff1b, targetHashCoinbaseBytes.ToBigInteger()) * shareMultiplier} - [stratum: {context.Difficulty} - blockTemplate: {KaspaUtils.TargetToDifficulty(KaspaUtils.CompactToBig(BlockTemplate.Header.Bits)) * (double) KaspaConstants.MinHash}]"); + + // calc share-diff + var shareDiff = (double) new BigRational(KaspaConstants.Diff1b, targetHashCoinbaseBytes.ToBigInteger()) * shareMultiplier; + + // diff check + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; + + // check if the share meets the much harder block difficulty (block candidate) + var isBlockCandidate = hashCoinbaseBytesValue <= blockTargetValue; + //var isBlockCandidate = true; + + // test if share meets at least workers current difficulty + 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) + { + ratio = shareDiff / context.PreviousDifficulty.Value; + + if(ratio < 0.99) + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + + // use previous difficulty + stratumDifficulty = context.PreviousDifficulty.Value; + } + + else + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + } + + var result = new Share + { + BlockHeight = (long) BlockTemplate.Header.DaaScore, + NetworkDifficulty = Difficulty, + Difficulty = context.Difficulty / shareMultiplier + }; + + if(isBlockCandidate) + { + var hashBytes = SerializeHeader(BlockTemplate.Header, false); + + result.IsBlockCandidate = true; + result.BlockHash = hashBytes.ToHexString(); + } + + return result; + } } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/Custom/Pyrin/PyrinJob.cs b/src/Miningcore/Blockchain/Kaspa/Custom/Pyrin/PyrinJob.cs index 7896b3fdbe..ed136c97ad 100644 --- a/src/Miningcore/Blockchain/Kaspa/Custom/Pyrin/PyrinJob.cs +++ b/src/Miningcore/Blockchain/Kaspa/Custom/Pyrin/PyrinJob.cs @@ -1,5 +1,4 @@ using System.Text; -using Miningcore.Contracts; using Miningcore.Crypto; using Miningcore.Crypto.Hashing.Algorithms; using Miningcore.Extensions; @@ -10,5 +9,5 @@ public class PyrinJob : KaspaJob { public PyrinJob(IHashAlgorithm customBlockHeaderHasher, IHashAlgorithm customCoinbaseHasher, IHashAlgorithm customShareHasher) : base(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher) { - } + } } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/Custom/Spectre/SpectreJob.cs b/src/Miningcore/Blockchain/Kaspa/Custom/Spectre/SpectreJob.cs new file mode 100644 index 0000000000..a06f76f0cd --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/Custom/Spectre/SpectreJob.cs @@ -0,0 +1,130 @@ +using System; +using System.Numerics; +using Miningcore.Contracts; +using Miningcore.Crypto; +using Miningcore.Crypto.Hashing.Algorithms; +using Miningcore.Extensions; +using Miningcore.Native; +using Miningcore.Stratum; +using Miningcore.Util; +using NBitcoin; +using kaspad = Miningcore.Blockchain.Kaspa.Kaspad; + +namespace Miningcore.Blockchain.Kaspa.Custom.Spectre; + +public class SpectreJob : KaspaJob +{ + protected AstroBWTv3 astroBWTv3Hasher; + + public SpectreJob(IHashAlgorithm customBlockHeaderHasher, IHashAlgorithm customCoinbaseHasher, IHashAlgorithm customShareHasher) : base(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher) + { + this.astroBWTv3Hasher = new AstroBWTv3(); + } + + protected override Span SerializeCoinbase(Span prePowHash, long timestamp, ulong nonce) + { + using(var stream = new MemoryStream()) + { + stream.Write(prePowHash); + stream.Write(BitConverter.GetBytes((ulong) timestamp)); + stream.Write(new byte[32]); // 32 zero bytes padding + stream.Write(BitConverter.GetBytes(nonce)); + + return (Span) stream.ToArray(); + } + } + + protected override Share ProcessShareInternal(StratumConnection worker, string nonce) + { + var context = worker.ContextAs(); + + BlockTemplate.Header.Nonce = Convert.ToUInt64(nonce, 16); + + var prePowHashBytes = SerializeHeader(BlockTemplate.Header, true); + var coinbaseRawBytes = SerializeCoinbase(prePowHashBytes, BlockTemplate.Header.Timestamp, BlockTemplate.Header.Nonce); + + Span coinbaseBytes = stackalloc byte[32]; + coinbaseHasher.Digest(coinbaseRawBytes, coinbaseBytes); + + Span astroBWTv3Bytes = stackalloc byte[32]; + astroBWTv3Hasher.Digest(coinbaseBytes, astroBWTv3Bytes); + + Span hashCoinbaseBytes = stackalloc byte[32]; + shareHasher.Digest(ComputeCoinbase(coinbaseRawBytes, astroBWTv3Bytes), hashCoinbaseBytes); + + var targetHashCoinbaseBytes = new Target(new BigInteger(hashCoinbaseBytes.ToNewReverseArray(), true, true)); + var hashCoinbaseBytesValue = targetHashCoinbaseBytes.ToUInt256(); + //throw new StratumException(StratumError.LowDifficultyShare, $"nonce: {nonce} ||| hashCoinbaseBytes: {hashCoinbaseBytes.ToHexString()} ||| BigInteger: {targetHashCoinbaseBytes.ToBigInteger()} ||| Target: {hashCoinbaseBytesValue} - [stratum: {KaspaUtils.DifficultyToTarget(context.Difficulty)} - blockTemplate: {blockTargetValue}] ||| BigToCompact: {KaspaUtils.BigToCompact(targetHashCoinbaseBytes.ToBigInteger())} - [stratum: {KaspaUtils.BigToCompact(KaspaUtils.DifficultyToTarget(context.Difficulty))} - blockTemplate: {BlockTemplate.Header.Bits}] ||| shareDiff: {(double) new BigRational(SpectreConstants.Diff1b, targetHashCoinbaseBytes.ToBigInteger()) * shareMultiplier} - [stratum: {context.Difficulty} - blockTemplate: {KaspaUtils.TargetToDifficulty(KaspaUtils.CompactToBig(BlockTemplate.Header.Bits)) * (double) SpectreConstants.MinHash}]"); + + // calc share-diff + var shareDiff = (double) new BigRational(SpectreConstants.Diff1b, targetHashCoinbaseBytes.ToBigInteger()) * shareMultiplier; + + // diff check + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; + + // check if the share meets the much harder block difficulty (block candidate) + var isBlockCandidate = hashCoinbaseBytesValue <= blockTargetValue; + //var isBlockCandidate = true; + + // test if share meets at least workers current difficulty + 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) + { + ratio = shareDiff / context.PreviousDifficulty.Value; + + if(ratio < 0.99) + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + + // use previous difficulty + stratumDifficulty = context.PreviousDifficulty.Value; + } + + else + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + } + + var result = new Share + { + BlockHeight = (long) BlockTemplate.Header.DaaScore, + NetworkDifficulty = Difficulty, + Difficulty = context.Difficulty / shareMultiplier + }; + + if(isBlockCandidate) + { + var hashBytes = SerializeHeader(BlockTemplate.Header, false); + + result.IsBlockCandidate = true; + result.BlockHash = hashBytes.ToHexString(); + } + + return result; + } + + public override void Init(kaspad.RpcBlock blockTemplate, string jobId, double shareMultiplier) + { + Contract.RequiresNonNull(blockTemplate); + Contract.Requires(!string.IsNullOrEmpty(jobId)); + Contract.RequiresNonNull(shareMultiplier); + + JobId = jobId; + this.shareMultiplier = shareMultiplier; + + var target = new Target(KaspaUtils.CompactToBig(blockTemplate.Header.Bits)); + Difficulty = KaspaUtils.TargetToDifficulty(target.ToBigInteger()) * (double) SpectreConstants.MinHash; + blockTargetValue = target.ToUInt256(); + BlockTemplate = blockTemplate; + + var (largeJob, regularJob) = SerializeJobParamsData(SerializeHeader(blockTemplate.Header)); + jobParams = new object[] + { + JobId, + largeJob + BitConverter.GetBytes(blockTemplate.Header.Timestamp).ToHexString().PadLeft(16, '0'), + regularJob, + blockTemplate.Header.Timestamp, + }; + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaConstants.cs b/src/Miningcore/Blockchain/Kaspa/KaspaConstants.cs index f66b74b388..3f1ca003ce 100644 --- a/src/Miningcore/Blockchain/Kaspa/KaspaConstants.cs +++ b/src/Miningcore/Blockchain/Kaspa/KaspaConstants.cs @@ -6,62 +6,27 @@ namespace Miningcore.Blockchain.Kaspa; -public static class BugnaConstants -{ - // List of BGA prefixes: https://github.com/bugnanetwork/bugnad/blob/master/util/address.go - public const string ChainPrefixDevnet = "bugnadev"; - public const string ChainPrefixSimnet = "bugnasim"; - public const string ChainPrefixTestnet = "bugnatest"; - public const string ChainPrefixMainnet = "bugna"; -} - -public static class HoosatConstants -{ - // List of HTN prefixes: https://github.com/Hoosat-Oy/HTND/blob/master/util/address.go - public const string ChainPrefixDevnet = "htndev"; - public const string ChainPrefixSimnet = "hoosatsim"; - public const string ChainPrefixTestnet = "hoosattest"; - public const string ChainPrefixMainnet = "hoosat"; -} - -public static class KobradagConstants -{ - // List of Kobra prefixes: - public const string ChainPrefixDevnet = "kobradev"; - public const string ChainPrefixSimnet = "kobrasim"; - public const string ChainPrefixTestnet = "kobratest"; - public const string ChainPrefixMainnet = "kobra"; -} - public static class KaspaConstants { public const string WalletDaemonCategory = "wallet"; public const int Diff1TargetNumZero = 31; - public static readonly BigInteger Diff1b = BigInteger.Parse("00000000ffff0000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); + public static readonly BigInteger Diff1b = BigInteger.Parse("00ffff0000000000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); public static BigInteger Diff1 = BigInteger.Pow(2, 256); public static BigInteger Diff1Target = BigInteger.Pow(2, 255) - 1; public static readonly double Pow2xDiff1TargetNumZero = Math.Pow(2, Diff1TargetNumZero); - public static BigInteger BigOne = BigInteger.One; - public static BigInteger OneLsh256 = BigInteger.One << 256; public static BigInteger MinHash = BigInteger.Divide(Diff1, Diff1Target); - public static BigInteger BigGig = BigInteger.Pow(10, 9); public const int ExtranoncePlaceHolderLength = 8; public static int NonceLength = 16; - public const uint ShareMultiplier = 1; // KAS smallest unit is called SOMPI: https://github.com/kaspanet/kaspad/blob/master/util/amount.go public const decimal SmallestUnit = 100000000; - // List of KAS prefixes: https://github.com/kaspanet/kaspad/blob/master/util/address.go - public const string ChainPrefixDevnet = "kaspadev"; - public const string ChainPrefixSimnet = "kaspasim"; - public const string ChainPrefixTestnet = "kaspatest"; - public const string ChainPrefixMainnet = "kaspa"; - public static readonly Regex RegexUserAgentBzMiner = new("bzminer", RegexOptions.Compiled | RegexOptions.IgnoreCase); public static readonly Regex RegexUserAgentIceRiverMiner = new("iceriverminer", RegexOptions.Compiled | RegexOptions.IgnoreCase); public static readonly Regex RegexUserAgentGodMiner = new("godminer", RegexOptions.Compiled | RegexOptions.IgnoreCase); + public static readonly Regex RegexUserAgentGoldShell = new("(goldshell|bzminer)", RegexOptions.Compiled | RegexOptions.IgnoreCase); + public static readonly Regex RegexUserAgentTNNMiner = new("tnn-miner", RegexOptions.Compiled | RegexOptions.IgnoreCase); public const string CoinbaseBlockHash = "BlockHash"; public const string CoinbaseProofOfWorkHash = "ProofOfWorkHash"; @@ -84,81 +49,25 @@ public static class KaspaConstants public const int Blake2bSize256 = 32; } -public static class KaspaClassicConstants -{ - // List of CAS prefixes: https://github.com/kaspaclassic/caspad/blob/main/util/address.go - public const string ChainPrefixDevnet = "caspadev"; - public const string ChainPrefixSimnet = "pyrinsim"; - public const string ChainPrefixTestnet = "pyrintest"; - public const string ChainPrefixMainnet = "cas"; -} - public static class KarlsencoinConstants -{ - // List of KLS prefixes: https://github.com/karlsen-network/karlsend/blob/master/util/address.go - public const string ChainPrefixDevnet = "karlsendev"; - public const string ChainPrefixSimnet = "karlsensim"; - public const string ChainPrefixTestnet = "karlsentest"; - public const string ChainPrefixMainnet = "karlsen"; - - public const long FishHashForkHeightTestnet = 0; - public const long FishHashPlusForkHeightTestnet = 6000000; -} - -public static class ConsensusConstants -{ - // List of CSS prefixes: https://github.com/consensus-network/consensusd/blob/master/util/address.go - public const string ChainPrefixDevnet = "consensusdev"; - public const string ChainPrefixSimnet = "consensussim"; - public const string ChainPrefixTestnet = "consensustest"; - public const string ChainPrefixMainnet = "consensus"; -} - -public static class PugdagConstants -{ - // List of PUG prefixes: https://github.com/Pugdag/pugdagd/blob/main/util/address.go - public const string ChainPrefixDevnet = "pugdagdev"; - public const string ChainPrefixSimnet = "pugdagsim"; - public const string ChainPrefixTestnet = "pugdagtest"; - public const string ChainPrefixMainnet = "pugdag"; -} - -public static class NautilusConstants -{ - // List of NTL prefixes: https://github.com/Nautilus-Network/nautiliad/blob/master/util/address.go - public const string ChainPrefixDevnet = "nautiliadev"; - public const string ChainPrefixSimnet = "nautilussim"; - public const string ChainPrefixTestnet = "nautilustest"; - public const string ChainPrefixMainnet = "nautilus"; -} - -public static class NexelliaConstants -{ - // List of NXL prefixes: https://github.com/Nexellia-Network/nexelliad/blob/master/util/address.go - public const string ChainPrefixDevnet = "nexelliadev"; - public const string ChainPrefixSimnet = "nexelliasim"; - public const string ChainPrefixTestnet = "nexelliatest"; - public const string ChainPrefixMainnet = "nexellia"; +{ + public const ulong FishHashForkHeightTestnet = 0; + public const ulong FishHashPlusForkHeightTestnet = 43200; + public const ulong FishHashPlusForkHeightMainnet = 26962009; } +// Pyrin is definitely a scam, use at your own risk public static class PyrinConstants -{ - // List of KLS prefixes: https://github.com/Pyrinpyi/pyipad/blob/master/util/address.go - public const string ChainPrefixDevnet = "pyipadev"; - public const string ChainPrefixSimnet = "pyrinsim"; - public const string ChainPrefixTestnet = "pyrintest"; - public const string ChainPrefixMainnet = "pyrin"; - - public const long Blake3ForkHeight = 1484741; +{ + public const ulong Blake3ForkHeight = 1484741; } -public static class SedraCoinConstants +public static class SpectreConstants { - // List of HTN prefixes: https://github.com/sedracoin/sedrad/blob/main/util/address.go - public const string ChainPrefixDevnet = "sedradev"; - public const string ChainPrefixSimnet = "sedrasim"; - public const string ChainPrefixTestnet = "sedratest"; - public const string ChainPrefixMainnet = "sedra"; + public const int Diff1TargetNumZero = 7; + public static readonly BigInteger Diff1b = BigInteger.Parse("00ffff0000000000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); + public static readonly double Pow2xDiff1TargetNumZero = Math.Pow(2, Diff1TargetNumZero); + public static BigInteger MinHash = BigInteger.One; } public enum KaspaBech32Prefix diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaJob.cs b/src/Miningcore/Blockchain/Kaspa/KaspaJob.cs index e1b41e7c6c..ad64a1e77c 100644 --- a/src/Miningcore/Blockchain/Kaspa/KaspaJob.cs +++ b/src/Miningcore/Blockchain/Kaspa/KaspaJob.cs @@ -56,12 +56,13 @@ private static ulong RotateRight64(ulong value, int offset) public class KaspaJob { protected IMasterClock clock; - public kaspad.RpcBlock BlockTemplate { get; private set; } - public double Difficulty { get; private set; } + protected double shareMultiplier; + public kaspad.RpcBlock BlockTemplate { get; protected set; } + public double Difficulty { get; protected set; } public string JobId { get; protected set; } public uint256 blockTargetValue { get; protected set; } - private object[] jobParams; + protected object[] jobParams; private readonly ConcurrentDictionary submissions = new(StringComparer.OrdinalIgnoreCase); protected IHashAlgorithm blockHeaderHasher; @@ -200,7 +201,7 @@ protected virtual Span SerializeCoinbase(Span prePowHash, long times } } - protected virtual Span SerializeHeader(kaspad.RpcBlockHeader header, bool isPrePow = true, bool isLittleEndian = false) + protected virtual Span SerializeHeader(kaspad.RpcBlockHeader header, bool isPrePow = true) { ulong nonce = isPrePow ? 0 : header.Nonce; long timestamp = isPrePow ? 0 : header.Timestamp; @@ -209,14 +210,14 @@ protected virtual Span SerializeHeader(kaspad.RpcBlockHeader header, bool using(var stream = new MemoryStream()) { - var versionBytes = (isLittleEndian) ? BitConverter.GetBytes((ushort) header.Version).ReverseInPlace() : BitConverter.GetBytes((ushort) header.Version); + var versionBytes = (!BitConverter.IsLittleEndian) ? BitConverter.GetBytes((ushort) header.Version).ReverseInPlace() : BitConverter.GetBytes((ushort) header.Version); stream.Write(versionBytes); - var parentsBytes = (isLittleEndian) ? BitConverter.GetBytes((ulong) header.Parents.Count).ReverseInPlace() : BitConverter.GetBytes((ulong) header.Parents.Count); + var parentsBytes = (!BitConverter.IsLittleEndian) ? BitConverter.GetBytes((ulong) header.Parents.Count).ReverseInPlace() : BitConverter.GetBytes((ulong) header.Parents.Count); stream.Write(parentsBytes); foreach (var parent in header.Parents) { - var parentHashesBytes = (isLittleEndian) ? BitConverter.GetBytes((ulong) parent.ParentHashes.Count).ReverseInPlace() : BitConverter.GetBytes((ulong) parent.ParentHashes.Count); + var parentHashesBytes = (!BitConverter.IsLittleEndian) ? BitConverter.GetBytes((ulong) parent.ParentHashes.Count).ReverseInPlace() : BitConverter.GetBytes((ulong) parent.ParentHashes.Count); stream.Write(parentHashesBytes); foreach (var parentHash in parent.ParentHashes) @@ -229,21 +230,21 @@ protected virtual Span SerializeHeader(kaspad.RpcBlockHeader header, bool stream.Write(header.AcceptedIdMerkleRoot.HexToByteArray()); stream.Write(header.UtxoCommitment.HexToByteArray()); - var timestampBytes = (isLittleEndian) ? BitConverter.GetBytes((ulong) timestamp).ReverseInPlace() : BitConverter.GetBytes((ulong) timestamp); + var timestampBytes = (!BitConverter.IsLittleEndian) ? BitConverter.GetBytes((ulong) timestamp).ReverseInPlace() : BitConverter.GetBytes((ulong) timestamp); stream.Write(timestampBytes); - var bitsBytes = (isLittleEndian) ? BitConverter.GetBytes(header.Bits).ReverseInPlace() : BitConverter.GetBytes(header.Bits); + var bitsBytes = (!BitConverter.IsLittleEndian) ? BitConverter.GetBytes(header.Bits).ReverseInPlace() : BitConverter.GetBytes(header.Bits); stream.Write(bitsBytes); - var nonceBytes = (isLittleEndian) ? BitConverter.GetBytes(nonce).ReverseInPlace() : BitConverter.GetBytes(nonce); + var nonceBytes = (!BitConverter.IsLittleEndian) ? BitConverter.GetBytes(nonce).ReverseInPlace() : BitConverter.GetBytes(nonce); stream.Write(nonceBytes); - var daaScoreBytes = (isLittleEndian) ? BitConverter.GetBytes(header.DaaScore).ReverseInPlace() : BitConverter.GetBytes(header.DaaScore); + var daaScoreBytes = (!BitConverter.IsLittleEndian) ? BitConverter.GetBytes(header.DaaScore).ReverseInPlace() : BitConverter.GetBytes(header.DaaScore); stream.Write(daaScoreBytes); - var blueScoreBytes = (isLittleEndian) ? BitConverter.GetBytes(header.BlueScore).ReverseInPlace() : BitConverter.GetBytes(header.BlueScore); + var blueScoreBytes = (!BitConverter.IsLittleEndian) ? BitConverter.GetBytes(header.BlueScore).ReverseInPlace() : BitConverter.GetBytes(header.BlueScore); stream.Write(blueScoreBytes); var blueWork = header.BlueWork.PadLeft(header.BlueWork.Length + (header.BlueWork.Length % 2), '0'); var blueWorkBytes = blueWork.HexToByteArray(); - var blueWorkLengthBytes = (isLittleEndian) ? BitConverter.GetBytes((ulong) blueWorkBytes.Length).ReverseInPlace() : BitConverter.GetBytes((ulong) blueWorkBytes.Length); + var blueWorkLengthBytes = (!BitConverter.IsLittleEndian) ? BitConverter.GetBytes((ulong) blueWorkBytes.Length).ReverseInPlace() : BitConverter.GetBytes((ulong) blueWorkBytes.Length); stream.Write(blueWorkLengthBytes); stream.Write(blueWorkBytes); @@ -255,14 +256,14 @@ protected virtual Span SerializeHeader(kaspad.RpcBlockHeader header, bool } } - protected virtual (string, ulong[]) SerializeJobParamsData(Span prePowHash, bool isLittleEndian = false) + protected virtual (string, ulong[]) SerializeJobParamsData(Span prePowHash) { ulong[] preHashU64s = new ulong[4]; string preHashStrings = ""; for (int i = 0; i < 4; i++) { - var slice = (isLittleEndian) ? prePowHash.Slice(i * 8, 8).ToNewReverseArray() : prePowHash.Slice(i * 8, 8); + var slice = prePowHash.Slice(i * 8, 8); preHashStrings += slice.ToHexString().PadLeft(16, '0'); preHashU64s[i] = BitConverter.ToUInt64(slice); @@ -274,24 +275,21 @@ protected virtual (string, ulong[]) SerializeJobParamsData(Span prePowHash protected virtual Share ProcessShareInternal(StratumConnection worker, string nonce) { var context = worker.ContextAs(); - + BlockTemplate.Header.Nonce = Convert.ToUInt64(nonce, 16); - + var prePowHashBytes = SerializeHeader(BlockTemplate.Header, true); var coinbaseBytes = SerializeCoinbase(prePowHashBytes, BlockTemplate.Header.Timestamp, BlockTemplate.Header.Nonce); + Span hashCoinbaseBytes = stackalloc byte[32]; + shareHasher.Digest(ComputeCoinbase(prePowHashBytes, coinbaseBytes), hashCoinbaseBytes); - if(shareHasher is not FishHashKarlsen) - shareHasher.Digest(ComputeCoinbase(prePowHashBytes, coinbaseBytes), hashCoinbaseBytes); - else - shareHasher.Digest(coinbaseBytes, hashCoinbaseBytes); - var targetHashCoinbaseBytes = new Target(new BigInteger(hashCoinbaseBytes.ToNewReverseArray(), true, true)); var hashCoinbaseBytesValue = targetHashCoinbaseBytes.ToUInt256(); - //throw new StratumException(StratumError.LowDifficultyShare, $"nonce: {nonce} ||| BigInteger: {targetHashCoinbaseBytes.ToBigInteger()} ||| Target: {hashCoinbaseBytesValue} - [stratum: {KaspaUtils.DifficultyToTarget(context.Difficulty)} - blockTemplate: {blockTargetValue}] ||| BigToCompact: {KaspaUtils.BigToCompact(targetHashCoinbaseBytes.ToBigInteger())} - [stratum: {KaspaUtils.BigToCompact(KaspaUtils.DifficultyToTarget(context.Difficulty))} - blockTemplate: {BlockTemplate.Header.Bits}] ||| shareDiff: {(double) new BigRational(KaspaConstants.Diff1b, targetHashCoinbaseBytes.ToBigInteger()) * (double) KaspaConstants.MinHash / KaspaConstants.ShareMultiplier} - [stratum: {context.Difficulty} - blockTemplate: {KaspaUtils.TargetToDifficulty(KaspaUtils.CompactToBig(BlockTemplate.Header.Bits)) * (double) KaspaConstants.MinHash / KaspaConstants.ShareMultiplier}] ||| AdjustShareDifficulty: {(double) new BigRational(KaspaConstants.Diff1b, targetHashCoinbaseBytes.ToBigInteger()) * KaspaConstants.Pow2xDiff1TargetNumZero * (double) KaspaConstants.MinHash / KaspaConstants.ShareMultiplier} - [stratum: {context.Difficulty * KaspaConstants.Pow2xDiff1TargetNumZero * (double) KaspaConstants.MinHash / KaspaConstants.ShareMultiplier}]"); - + //throw new StratumException(StratumError.LowDifficultyShare, $"nonce: {nonce} ||| hashCoinbaseBytes: {hashCoinbaseBytes.ToHexString()} ||| BigInteger: {targetHashCoinbaseBytes.ToBigInteger()} ||| Target: {hashCoinbaseBytesValue} - [stratum: {KaspaUtils.DifficultyToTarget(context.Difficulty)} - blockTemplate: {blockTargetValue}] ||| BigToCompact: {KaspaUtils.BigToCompact(targetHashCoinbaseBytes.ToBigInteger())} - [stratum: {KaspaUtils.BigToCompact(KaspaUtils.DifficultyToTarget(context.Difficulty))} - blockTemplate: {BlockTemplate.Header.Bits}] ||| shareDiff: {(double) new BigRational(KaspaConstants.Diff1b, targetHashCoinbaseBytes.ToBigInteger()) * shareMultiplier} - [stratum: {context.Difficulty} - blockTemplate: {KaspaUtils.TargetToDifficulty(KaspaUtils.CompactToBig(BlockTemplate.Header.Bits)) * (double) KaspaConstants.MinHash}]"); + // calc share-diff - var shareDiff = (double) new BigRational(KaspaConstants.Diff1b, targetHashCoinbaseBytes.ToBigInteger()) * KaspaConstants.Pow2xDiff1TargetNumZero * (double) KaspaConstants.MinHash / KaspaConstants.ShareMultiplier; + var shareDiff = (double) new BigRational(KaspaConstants.Diff1b, targetHashCoinbaseBytes.ToBigInteger()) * shareMultiplier; // diff check var stratumDifficulty = context.Difficulty; @@ -324,7 +322,7 @@ protected virtual Share ProcessShareInternal(StratumConnection worker, string no { BlockHeight = (long) BlockTemplate.Header.DaaScore, NetworkDifficulty = Difficulty, - Difficulty = context.Difficulty / KaspaConstants.ShareMultiplier + Difficulty = context.Difficulty / shareMultiplier }; if(isBlockCandidate) @@ -366,14 +364,17 @@ public virtual Share ProcessShare(StratumConnection worker, string nonce) return ProcessShareInternal(worker, nonce); } - public void Init(kaspad.RpcBlock blockTemplate, string jobId) + public virtual void Init(kaspad.RpcBlock blockTemplate, string jobId, double shareMultiplier) { Contract.RequiresNonNull(blockTemplate); - Contract.RequiresNonNull(jobId); + Contract.Requires(!string.IsNullOrEmpty(jobId)); + Contract.RequiresNonNull(shareMultiplier); JobId = jobId; + this.shareMultiplier = shareMultiplier; + var target = new Target(KaspaUtils.CompactToBig(blockTemplate.Header.Bits)); - Difficulty = KaspaUtils.TargetToDifficulty(target.ToBigInteger()) * (double) KaspaConstants.MinHash / KaspaConstants.ShareMultiplier; + Difficulty = KaspaUtils.TargetToDifficulty(target.ToBigInteger()) * (double) KaspaConstants.MinHash; blockTargetValue = target.ToUInt256(); BlockTemplate = blockTemplate; diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaJobManager.cs b/src/Miningcore/Blockchain/Kaspa/KaspaJobManager.cs index d5d35042cf..bc2a8b5c01 100644 --- a/src/Miningcore/Blockchain/Kaspa/KaspaJobManager.cs +++ b/src/Miningcore/Blockchain/Kaspa/KaspaJobManager.cs @@ -13,8 +13,10 @@ using Grpc.Core; using Grpc.Net.Client; using Miningcore.Blockchain.Kaspa.Configuration; +using Miningcore.Blockchain.Kaspa.Custom.Astrix; using Miningcore.Blockchain.Kaspa.Custom.Karlsencoin; using Miningcore.Blockchain.Kaspa.Custom.Pyrin; +using Miningcore.Blockchain.Kaspa.Custom.Spectre; using NLog; using Miningcore.Configuration; using Miningcore.Crypto; @@ -55,7 +57,6 @@ public KaspaJobManager( private kaspad.KaspadRPC.KaspadRPCClient rpc; private kaspaWalletd.KaspaWalletdRPC.KaspaWalletdRPCClient walletRpc; private string network; - private readonly List validJobs = new(); private readonly IExtraNonceProvider extraNonceProvider; private readonly IMasterClock clock; private KaspaPoolConfigExtra extraPoolConfig; @@ -140,7 +141,7 @@ public KaspaJobManager( catch(NullReferenceException) { // The following is weird but correct, when all data has been received `streamNotifyNewBlockTemplate.ResponseStream.ReadAllAsync()` will return a `NullReferenceException` - logger.Debug(() => $"Waiting for data..."); + logger.Info(() => $"Waiting for `NewBlockTemplate` data..."); goto retry_blocktemplate; } @@ -211,39 +212,35 @@ private void SetupJobUpdates(CancellationToken ct) .RefCount(); } - private KaspaJob CreateJob(long blockHeight) + private KaspaJob CreateJob(ulong blockHeight) { switch(coin.Symbol) { - case "CAS": - case "HTN": - if(customBlockHeaderHasher is not Blake3IHash) - { - string coinbaseBlockHash = KaspaConstants.CoinbaseBlockHash; - byte[] hashBytes = Encoding.UTF8.GetBytes(coinbaseBlockHash.PadRight(32, '\0')).Take(32).ToArray(); - customBlockHeaderHasher = new Blake3IHash(hashBytes); - } + case "AIX": + if(customBlockHeaderHasher is not Blake2b) + customBlockHeaderHasher = new Blake2b(Encoding.UTF8.GetBytes(KaspaConstants.CoinbaseBlockHash)); - if(customCoinbaseHasher is not Blake3IHash) - customCoinbaseHasher = new Blake3IHash(); + if(customCoinbaseHasher is not CShake256) + customCoinbaseHasher = new CShake256(null, Encoding.UTF8.GetBytes(KaspaConstants.CoinbaseProofOfWorkHash)); - if(customShareHasher is not Blake3IHash) - customShareHasher = new Blake3IHash(); + if(customShareHasher is not CShake256) + customShareHasher = new CShake256(null, Encoding.UTF8.GetBytes(KaspaConstants.CoinbaseHeavyHash)); - return new PyrinJob(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher); - case "KODA": - if(customBlockHeaderHasher is not Blake3IHash) + return new AstrixJob(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher); + case "CAS": + case "HTN": + if(customBlockHeaderHasher is not Blake3) { string coinbaseBlockHash = KaspaConstants.CoinbaseBlockHash; byte[] hashBytes = Encoding.UTF8.GetBytes(coinbaseBlockHash.PadRight(32, '\0')).Take(32).ToArray(); - customBlockHeaderHasher = new Blake3IHash(hashBytes); + customBlockHeaderHasher = new Blake3(hashBytes); } - if(customCoinbaseHasher is not Blake3IHash) - customCoinbaseHasher = new Blake3IHash(); + if(customCoinbaseHasher is not Blake3) + customCoinbaseHasher = new Blake3(); - if(customShareHasher is not Blake3IHash) - customShareHasher = new Blake3IHash(); + if(customShareHasher is not Blake3) + customShareHasher = new Blake3(); return new PyrinJob(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher); case "KLS": @@ -252,36 +249,28 @@ private KaspaJob CreateJob(long blockHeight) if(customBlockHeaderHasher is not Blake2b) customBlockHeaderHasher = new Blake2b(Encoding.UTF8.GetBytes(KaspaConstants.CoinbaseBlockHash)); - if(customCoinbaseHasher is not Blake3IHash) - customCoinbaseHasher = new Blake3IHash(); + if(customCoinbaseHasher is not Blake3) + customCoinbaseHasher = new Blake3(); - if(karlsenNetwork == "testnet" && blockHeight >= KarlsencoinConstants.FishHashPlusForkHeightTestnet) + if((karlsenNetwork == "testnet" && blockHeight >= KarlsencoinConstants.FishHashPlusForkHeightTestnet) || (karlsenNetwork == "mainnet" && blockHeight >= KarlsencoinConstants.FishHashPlusForkHeightMainnet)) { logger.Debug(() => $"fishHashPlusHardFork activated"); if(customShareHasher is not FishHashKarlsen) + customShareHasher = new FishHashKarlsen(FishHash.FishHashKernelPlus); + else if(customShareHasher is FishHashKarlsen fishHashKarlsenAlgo) { - var started = DateTime.Now; - logger.Debug(() => $"Generating light cache"); - - customShareHasher = new FishHashKarlsen(true); - - logger.Debug(() => $"Done generating light cache after {DateTime.Now - started}"); + if(fishHashKarlsenAlgo.fishHashKernel != FishHash.FishHashKernelPlus) + customShareHasher = new FishHashKarlsen(FishHash.FishHashKernelPlus); } + } else if(karlsenNetwork == "testnet" && blockHeight >= KarlsencoinConstants.FishHashForkHeightTestnet) { logger.Debug(() => $"fishHashHardFork activated"); if(customShareHasher is not FishHashKarlsen) - { - var started = DateTime.Now; - logger.Debug(() => $"Generating light cache"); - customShareHasher = new FishHashKarlsen(); - - logger.Debug(() => $"Done generating light cache after {DateTime.Now - started}"); - } } else if(customShareHasher is not CShake256) @@ -289,14 +278,14 @@ private KaspaJob CreateJob(long blockHeight) return new KarlsencoinJob(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher); case "CSS": - case "PUG": case "NTL": case "NXL": + case "PUG": if(customBlockHeaderHasher is not Blake2b) customBlockHeaderHasher = new Blake2b(Encoding.UTF8.GetBytes(KaspaConstants.CoinbaseBlockHash)); - if(customCoinbaseHasher is not Blake3IHash) - customCoinbaseHasher = new Blake3IHash(); + if(customCoinbaseHasher is not Blake3) + customCoinbaseHasher = new Blake3(); if(customShareHasher is not CShake256) customShareHasher = new CShake256(null, Encoding.UTF8.GetBytes(KaspaConstants.CoinbaseHeavyHash)); @@ -307,18 +296,18 @@ private KaspaJob CreateJob(long blockHeight) { logger.Debug(() => $"blake3HardFork activated"); - if(customBlockHeaderHasher is not Blake3IHash) + if(customBlockHeaderHasher is not Blake3) { string coinbaseBlockHash = KaspaConstants.CoinbaseBlockHash; byte[] hashBytes = Encoding.UTF8.GetBytes(coinbaseBlockHash.PadRight(32, '\0')).Take(32).ToArray(); - customBlockHeaderHasher = new Blake3IHash(hashBytes); + customBlockHeaderHasher = new Blake3(hashBytes); } - if(customCoinbaseHasher is not Blake3IHash) - customCoinbaseHasher = new Blake3IHash(); + if(customCoinbaseHasher is not Blake3) + customCoinbaseHasher = new Blake3(); - if(customShareHasher is not Blake3IHash) - customShareHasher = new Blake3IHash(); + if(customShareHasher is not Blake3) + customShareHasher = new Blake3(); } else { @@ -333,6 +322,17 @@ private KaspaJob CreateJob(long blockHeight) } return new PyrinJob(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher); + case "SPR": + if(customBlockHeaderHasher is not Blake2b) + customBlockHeaderHasher = new Blake2b(Encoding.UTF8.GetBytes(KaspaConstants.CoinbaseBlockHash)); + + if(customCoinbaseHasher is not CShake256) + customCoinbaseHasher = new CShake256(null, Encoding.UTF8.GetBytes(KaspaConstants.CoinbaseProofOfWorkHash)); + + if(customShareHasher is not CShake256) + customShareHasher = new CShake256(null, Encoding.UTF8.GetBytes(KaspaConstants.CoinbaseHeavyHash)); + + return new SpectreJob(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher); } if(customBlockHeaderHasher is not Blake2b) @@ -369,18 +369,9 @@ private async Task UpdateJob(CancellationToken ct, string via = null, kasp if(isNew) { - job = CreateJob((long) blockTemplate.Header.DaaScore); - - job.Init(blockTemplate, NextJobId()); - - lock(jobLock) - { - validJobs.Insert(0, job); + job = CreateJob(blockTemplate.Header.DaaScore); - // trim active jobs - while(validJobs.Count > maxActiveJobs) - validJobs.RemoveAt(validJobs.Count - 1); - } + job.Init(blockTemplate, NextJobId("D"), ShareMultiplier); logger.Debug(() => $"blockTargetValue: {job.blockTargetValue}"); logger.Debug(() => $"Difficulty: {job.Difficulty}"); @@ -535,6 +526,18 @@ private async Task SubmitBlockAsync(CancellationToken ct, kaspad.RpcBlock return succeed; } + private object[] GetJobParamsForStratum() + { + var job = currentJob; + return job?.GetJobParams(); + } + + public override KaspaJob GetJobForStratum() + { + var job = currentJob; + return job; + } + #region API-Surface public IObservable Jobs { get; private set; } @@ -583,9 +586,21 @@ public virtual async ValueTask SubmitShareAsync(StratumConnection worker, KaspaJob job; - lock(jobLock) + lock(context) { - job = validJobs.FirstOrDefault(x => x.JobId == jobId); + job = context.GetJob(jobId); + + if(job == null) + { + // stupid hack for busted ass IceRiver/Bitmain ASICs. Need to loop + // through job history because they submit jobs with incorrect IDs + // https://github.com/rdugan/kaspa-stratum-bridge/blob/main/src/kaspastratum/share_handler.go#L216 + if(ValidateIsGodMiner(context.UserAgent) || ValidateIsIceRiverMiner(context.UserAgent)) + job = context.validJobs.ToArray().FirstOrDefault(x => Int64.Parse(x.JobId) < Int64.Parse(jobId)); + } + + if(job == null) + logger.Warn(() => $"[{context.Miner}] => jobId: {jobId} - Last known job: {context.validJobs.ToArray().FirstOrDefault()?.JobId}"); } if(job == null) @@ -643,6 +658,9 @@ public bool ValidateIsLargeJob(string userAgent) if(ValidateIsIceRiverMiner(userAgent)) return true; + + if(ValidateIsGoldShell(userAgent)) + return true; return false; } @@ -677,6 +695,28 @@ public bool ValidateIsIceRiverMiner(string userAgent) return (matchesUserAgentIceRiverMiner.Count > 0); } + public bool ValidateIsGoldShell(string userAgent) + { + if(string.IsNullOrEmpty(userAgent)) + return false; + + // Find matches + MatchCollection matchesUserAgentGoldShell = KaspaConstants.RegexUserAgentGoldShell.Matches(userAgent); + return (matchesUserAgentGoldShell.Count > 0); + } + + public bool ValidateIsTNNMiner(string userAgent) + { + if(string.IsNullOrEmpty(userAgent)) + return false; + + // Find matches + MatchCollection matchesUserAgentTNNMiner = KaspaConstants.RegexUserAgentTNNMiner.Matches(userAgent); + return (matchesUserAgentTNNMiner.Count > 0); + } + + public double ShareMultiplier => coin.ShareMultiplier; + #endregion // API-Surface #region Overrides @@ -702,13 +742,13 @@ await Guard(() => stream.RequestStream.WriteAsync(request), network = currentNetwork.GetCurrentNetworkResponse.CurrentNetwork; break; } - - var (kaspaAddressUtility, errorKaspaAddressUtility) = KaspaUtils.ValidateAddress(poolConfig.Address, network, coin.Symbol); + + var (kaspaAddressUtility, errorKaspaAddressUtility) = KaspaUtils.ValidateAddress(poolConfig.Address, network, coin); if(errorKaspaAddressUtility != null) throw new PoolStartupException($"Pool address: {poolConfig.Address} is invalid for network [{network}]: {errorKaspaAddressUtility}", poolConfig.Id); else logger.Info(() => $"Pool address: {poolConfig.Address} => {KaspaConstants.KaspaAddressType[kaspaAddressUtility.KaspaAddress.Version()]}"); - + // update stats BlockchainStats.NetworkType = network; BlockchainStats.RewardType = "POW"; @@ -735,7 +775,7 @@ await Guard(() => stream.RequestStream.WriteAsync(request), { // we need a call to communicate with kaspadWallet var call = walletRpc.ShowAddressesAsync(new kaspaWalletd.ShowAddressesRequest(), null, null, ct); - + // check configured address belongs to wallet var walletAddresses = await Guard(() => call.ResponseAsync, ex=> throw new PoolStartupException($"Error validating pool address '{ex.GetType().Name}' : {ex}", poolConfig.Id)); @@ -744,7 +784,7 @@ await Guard(() => stream.RequestStream.WriteAsync(request), if(!walletAddresses.Address.Contains(poolConfig.Address)) throw new PoolStartupException($"Pool address: {poolConfig.Address} is not controlled by pool wallet", poolConfig.Id); } - + await UpdateNetworkStatsAsync(ct); // Periodically update network stats @@ -764,15 +804,15 @@ public override void Configure(PoolConfig pc, ClusterConfig cc) extraPoolConfig = pc.Extra.SafeExtensionDataAs(); extraPoolPaymentProcessingConfig = pc.PaymentProcessing.Extra.SafeExtensionDataAs(); - + maxActiveJobs = extraPoolConfig?.MaxActiveJobs ?? 8; - extraData = extraPoolConfig?.ExtraData ?? "Miningcore"; - + extraData = extraPoolConfig?.ExtraData ?? "Miningcore.developers[\"Cedric CRISPIN\"]"; + // extract standard daemon endpoints daemonEndpoints = pc.Daemons .Where(x => string.IsNullOrEmpty(x.Category)) .ToArray(); - + if(cc.PaymentProcessing?.Enabled == true && pc.PaymentProcessing?.Enabled == true) { // extract wallet daemon endpoints @@ -935,11 +975,5 @@ await Guard(() => stream.RequestStream.WriteAsync(request), } while(await timer.WaitForNextTickAsync(ct)); } - private object[] GetJobParamsForStratum() - { - var job = currentJob; - return job?.GetJobParams(); - } - #endregion // Overrides } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaPayoutHandler.cs b/src/Miningcore/Blockchain/Kaspa/KaspaPayoutHandler.cs index 5ad881a519..a0bf982f4a 100644 --- a/src/Miningcore/Blockchain/Kaspa/KaspaPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Kaspa/KaspaPayoutHandler.cs @@ -1,5 +1,6 @@ using System; using System.Net.Http; +using System.Text.RegularExpressions; using Autofac; using AutoMapper; using Grpc.Core; @@ -52,6 +53,7 @@ public KaspaPayoutHandler( private string network; private KaspaPoolConfigExtra extraPoolConfig; private KaspaPaymentProcessingConfigExtra extraPoolPaymentProcessingConfig; + private bool supportsMaxFee = false; protected override string LogCategory => "Kaspa Payout Handler"; @@ -100,6 +102,31 @@ await Guard(() => stream.RequestStream.WriteAsync(request), break; } await stream.RequestStream.CompleteAsync(); + + var callGetVersion = walletRpc.GetVersionAsync(new kaspaWalletd.GetVersionRequest()); + var walletVersion = await Guard(() => callGetVersion.ResponseAsync, + ex=> logger.Debug(ex)); + callGetVersion.Dispose(); + + if(!string.IsNullOrEmpty(walletVersion?.Version)) + { + logger.Info(() => $"[{LogCategory}] Wallet version: {walletVersion.Version}"); + + if(!string.IsNullOrEmpty(extraPoolPaymentProcessingConfig?.VersionEnablingMaxFee)) + { + logger.Info(() => $"[{LogCategory}] Wallet daemon version which enables MaxFee: {extraPoolPaymentProcessingConfig.VersionEnablingMaxFee}"); + + string walletVersionNumbersOnly = Regex.Replace(walletVersion.Version, "[^0-9.]", ""); + string[] walletVersionNumbers = walletVersionNumbersOnly.Split("."); + + string versionEnablingMaxFeeNumbersOnly = Regex.Replace(extraPoolPaymentProcessingConfig.VersionEnablingMaxFee, "[^0-9.]", ""); + string[] versionEnablingMaxFeeNumbers = versionEnablingMaxFeeNumbersOnly.Split("."); + + // update supports max fee + if(walletVersionNumbers.Length >= 3 && versionEnablingMaxFeeNumbers.Length >= 3) + supportsMaxFee = ((Convert.ToUInt32(walletVersionNumbers[0]) > Convert.ToUInt32(versionEnablingMaxFeeNumbers[0])) || (Convert.ToUInt32(walletVersionNumbers[0]) == Convert.ToUInt32(versionEnablingMaxFeeNumbers[0]) && Convert.ToUInt32(walletVersionNumbers[1]) > Convert.ToUInt32(versionEnablingMaxFeeNumbers[1])) || (Convert.ToUInt32(walletVersionNumbers[0]) == Convert.ToUInt32(versionEnablingMaxFeeNumbers[0]) && Convert.ToUInt32(walletVersionNumbers[1]) == Convert.ToUInt32(versionEnablingMaxFeeNumbers[1]) && Convert.ToUInt32(walletVersionNumbers[2]) >= Convert.ToUInt32(versionEnablingMaxFeeNumbers[2]))); + } + } } public virtual async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, CancellationToken ct) @@ -114,6 +141,7 @@ public virtual async Task ClassifyBlocksAsync(IMiningPool pool, Block[] var pageSize = 100; var pageCount = (int) Math.Ceiling(blocks.Length / (double) pageSize); var result = new List(); + // KAS minimum confirmation can change over time so please always aknowledge all those different changes very wisely: https://github.com/kaspanet/rusty-kaspa/blob/master/wallet/core/src/utxo/settings.rs int minConfirmations = extraPoolPaymentProcessingConfig?.MinimumConfirmations ?? (network == "mainnet" ? 120 : 110); // we need a stream to communicate with Kaspad @@ -126,15 +154,27 @@ public virtual async Task ClassifyBlocksAsync(IMiningPool pool, Block[] .Skip(i * pageSize) .Take(pageSize) .ToArray(); - + for(var j = 0; j < page.Length; j++) { var block = page[j]; - + + // There is a case scenario: + // https://github.com/blackmennewstyle/miningcore/issues/191 + // Sadly miners can submit different solutions which will produce the exact same blockHash for the same block + // We must handle that case carefully here, otherwise we will overpay our miners. + // Only one of these blocks must will be confirmed, the others will all become Orphans + uint totalDuplicateBlockBefore = await cf.Run(con => blockRepo.GetPoolDuplicateBlockBeforeCountByPoolHeightAndHashNoTypeAndStatusAsync(con, poolConfig.Id, Convert.ToInt64(block.BlockHeight), block.Hash, new[] + { + BlockStatus.Confirmed, + BlockStatus.Orphaned, + BlockStatus.Pending + }, block.Created)); + var request = new kaspad.KaspadMessage(); request.GetBlockRequest = new kaspad.GetBlockRequestMessage { - Hash = (string) block.Hash, + Hash = block.Hash, IncludeTransactions = true, }; await Guard(() => stream.RequestStream.WriteAsync(request), @@ -153,6 +193,18 @@ await Guard(() => stream.RequestStream.WriteAsync(request), messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); } + // multiple blocks with the exact same height & hash recorded in the database + else if(totalDuplicateBlockBefore > 0) + { + result.Add(block); + + block.Status = BlockStatus.Orphaned; + block.Reward = 0; + + logger.Info(() => $"[{LogCategory}] Block {block.BlockHeight} [{block.Hash}] classified as orphaned because we already have in the database {totalDuplicateBlockBefore} block(s) with the same height and hash"); + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + } else { logger.Info(() => $"[{LogCategory}] Block {block.BlockHeight} uses a custom minimum confirmations calculation [{minConfirmations}]"); @@ -168,6 +220,8 @@ await Guard(() => stream.RequestStream.WriteAsync(requestConfirmations), ex=> logger.Debug(ex)); await foreach (var responseConfirmations in stream.ResponseStream.ReadAllAsync(ct)) { + logger.Debug(() => $"[{LogCategory}] Block {block.BlockHeight} [{responseConfirmations.GetBlocksResponse.BlockHashes.Count}]"); + block.ConfirmationProgress = Math.Min(1.0d, (double) responseConfirmations.GetBlocksResponse.BlockHashes.Count / minConfirmations); break; } @@ -317,6 +371,8 @@ public virtual async Task PayoutAsync(IMiningPool pool, Balance[] balances, Canc // build args var amounts = balances .Where(x => x.Amount > 0) + .OrderBy(x => x.Updated) + .ThenByDescending(x => x.Amount) .ToDictionary(x => x.Address, x => x.Amount); if(amounts.Count == 0) @@ -324,14 +380,14 @@ public virtual async Task PayoutAsync(IMiningPool pool, Balance[] balances, Canc var balancesTotal = amounts.Sum(x => x.Value); - logger.Info(() => $"[{LogCategory}] Paying {FormatAmount(balances.Sum(x => x.Amount))} to {balances.Length} addresses"); + logger.Info(() => $"[{LogCategory}] Paying {FormatAmount(balancesTotal)} to {balances.Length} addresses"); logger.Info(() => $"[{LogCategory}] Validating addresses..."); var coin = poolConfig.Template.As(); foreach(var pair in amounts) { logger.Debug(() => $"[{LogCategory}] Address {pair.Key} with amount [{FormatAmount(pair.Value)}]"); - var (kaspaAddressUtility, errorKaspaAddressUtility) = KaspaUtils.ValidateAddress(pair.Key, network, coin.Symbol); + var (kaspaAddressUtility, errorKaspaAddressUtility) = KaspaUtils.ValidateAddress(pair.Key, network, coin); if(errorKaspaAddressUtility != null) logger.Warn(()=> $"[{LogCategory}] Address {pair.Key} is not valid : {errorKaspaAddressUtility}"); @@ -353,57 +409,105 @@ public virtual async Task PayoutAsync(IMiningPool pool, Balance[] balances, Canc logger.Warn(() => $"[{LogCategory}] Wallet balance currently short of {FormatAmount(balancesTotal - walletBalanceAvailable)}. Will try again"); return; } - + var txFailures = new List, Exception>>(); var successBalances = new Dictionary(); - var parallelOptions = new ParallelOptions + // Payments on KASPA are a bit tricky, it does not have a strong multi-recipient method, the only way is to create unsigned transactions, signed them and then broadcast them, let's do this! + foreach (var amount in amounts) { - MaxDegreeOfParallelism = extraPoolPaymentProcessingConfig?.MaxDegreeOfParallelPayouts ?? 2, - CancellationToken = ct - }; + kaspaWalletd.CreateUnsignedTransactionsResponse unsignedTransaction; + kaspaWalletd.SignResponse signedTransaction; - await Parallel.ForEachAsync(amounts, parallelOptions, async (x, _ct) => - { - var (address, amount) = x; + // use a common id for all log entries related to this transfer + var transferId = CorrelationIdGenerator.GetNextId(); - await Guard(async () => + logger.Info(()=> $"[{LogCategory}] [{transferId}] Sending {FormatAmount(amount.Value)} to {amount.Key}"); + + logger.Info(()=> $"[{LogCategory}] [{transferId}] 1/3 Create an unsigned transaction"); + + var createUnsignedTransactionsRequest = new kaspaWalletd.CreateUnsignedTransactionsRequest { - // use a common id for all log entries related to this transfer - var transferId = CorrelationIdGenerator.GetNextId(); - - logger.Info(()=> $"[{LogCategory}] [{transferId}] Sending {FormatAmount(amount)} to {address}"); - - var callSend = walletRpc.SendAsync(new kaspaWalletd.SendRequest { - ToAddress = address.ToLower(), - Amount = (ulong) (amount * KaspaConstants.SmallestUnit), - Password = extraPoolPaymentProcessingConfig?.WalletPassword ?? null, - UseExistingChangeAddress = true, - IsSendAll = false, - }); - var sendTransaction = await Guard(() => callSend.ResponseAsync, - ex=> throw new PaymentException($"[{transferId}] kaspawalletd returned error: {ex}")); - callSend.Dispose(); + Address = amount.Key.ToLower(), + Amount = (ulong) (amount.Value * KaspaConstants.SmallestUnit), + UseExistingChangeAddress = false, + IsSendAll = false + }; - // check result - var txId = sendTransaction.TxIDs.First(); + if(supportsMaxFee) + { + ulong maxFee = extraPoolPaymentProcessingConfig?.MaxFee ?? 20000; - if(string.IsNullOrEmpty(txId)) - throw new Exception($"[{transferId}] kaspawalletd did not return a transaction id!"); - else - logger.Info(() => $"[{LogCategory}] [{transferId}] Payment transaction id: {txId}"); + logger.Info(()=> $"[{LogCategory}] Max fee: {maxFee} SOMPI"); - successBalances.Add(new Balance + createUnsignedTransactionsRequest.FeePolicy = new kaspaWalletd.FeePolicy { - PoolId = poolConfig.Id, - Address = address, - Amount = amount, - }, txId); - }, ex => + MaxFee = maxFee + }; + } + + var callUnsignedTransaction = walletRpc.CreateUnsignedTransactionsAsync(createUnsignedTransactionsRequest); + + unsignedTransaction = await Guard(() => callUnsignedTransaction.ResponseAsync, ex => { - txFailures.Add(Tuple.Create(x, ex)); + txFailures.Add(Tuple.Create(amount, ex)); }); - }); + callUnsignedTransaction.Dispose(); + + logger.Debug(()=> $"[{LogCategory}] [{transferId}] {(unsignedTransaction?.UnsignedTransactions == null ? 0 : unsignedTransaction?.UnsignedTransactions.Count)} unsigned transaction(s) created"); + + // we have transactions to sign + if(unsignedTransaction?.UnsignedTransactions.Count > 0) + { + logger.Info(()=> $"[{LogCategory}] [{transferId}] 2/3 Sign {unsignedTransaction.UnsignedTransactions.Count} unsigned transaction(s)"); + + var signRequest = new kaspaWalletd.SignRequest + { + Password = extraPoolPaymentProcessingConfig?.WalletPassword ?? null + }; + signRequest.UnsignedTransactions.Add(unsignedTransaction.UnsignedTransactions); + + var callSignedTransaction = walletRpc.SignAsync(signRequest); + signedTransaction = await Guard(() => callSignedTransaction.ResponseAsync, ex => + { + txFailures.Add(Tuple.Create(amount, ex)); + }); + callSignedTransaction.Dispose(); + + logger.Debug(()=> $"[{LogCategory}] [{transferId}] {(signedTransaction?.SignedTransactions == null ? 0 : signedTransaction?.SignedTransactions.Count)} signed transaction(s) created"); + + // we have transactions to broadcast + if(signedTransaction?.SignedTransactions.Count > 0) + { + var broadcastRequest = new kaspaWalletd.BroadcastRequest(); + kaspaWalletd.BroadcastResponse broadcastTransaction; + + logger.Info(()=> $"[{LogCategory}] [{transferId}] 3/3 Broadcast {signedTransaction.SignedTransactions.Count} signed transaction(s)"); + + broadcastRequest.Transactions.Add(signedTransaction.SignedTransactions); + var callBroadcast = walletRpc.BroadcastAsync(broadcastRequest); + broadcastTransaction = await Guard(() => callBroadcast.ResponseAsync, + ex=> logger.Warn(ex)); + callBroadcast.Dispose(); + + logger.Debug(()=> $"[{LogCategory}] {(broadcastTransaction?.TxIDs == null ? 0 : broadcastTransaction?.TxIDs.Count)} transaction ID(s) returned"); + + if(broadcastTransaction?.TxIDs.Count > 0) + { + var txId = broadcastTransaction?.TxIDs.First(); + + logger.Info(() => $"[{LogCategory}] [{amount.Key} - {FormatAmount(amount.Value)}] Payment transaction id: {txId}"); + + successBalances.Add(new Balance + { + PoolId = poolConfig.Id, + Address = amount.Key, + Amount = amount.Value, + }, txId); + } + } + } + } if(successBalances.Any()) { @@ -422,15 +526,35 @@ await Guard(async () => NotifyPayoutFailure(poolConfig.Id, failureBalances, error, null); } } - + public override double AdjustShareDifficulty(double difficulty) { - return difficulty * KaspaConstants.Pow2xDiff1TargetNumZero * (double) KaspaConstants.MinHash; + var coin = poolConfig.Template.As(); + + switch(coin.Symbol) + { + case "SPR": + + return difficulty * SpectreConstants.Pow2xDiff1TargetNumZero * (double) SpectreConstants.MinHash; + default: + + return difficulty * KaspaConstants.Pow2xDiff1TargetNumZero * (double) KaspaConstants.MinHash; + } } public double AdjustBlockEffort(double effort) { - return effort * KaspaConstants.Pow2xDiff1TargetNumZero * (double) KaspaConstants.MinHash; + var coin = poolConfig.Template.As(); + + switch(coin.Symbol) + { + case "SPR": + + return effort * SpectreConstants.Pow2xDiff1TargetNumZero * (double) SpectreConstants.MinHash; + default: + + return effort * KaspaConstants.Pow2xDiff1TargetNumZero * (double) KaspaConstants.MinHash; + } } #endregion // IPayoutHandler diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaPool.cs b/src/Miningcore/Blockchain/Kaspa/KaspaPool.cs index 019cafbe49..b539658c49 100644 --- a/src/Miningcore/Blockchain/Kaspa/KaspaPool.cs +++ b/src/Miningcore/Blockchain/Kaspa/KaspaPool.cs @@ -67,7 +67,18 @@ protected virtual async Task OnSubscribeAsync(StratumConnection connection, Time .Concat(manager.GetSubscriberData(connection)) .ToArray(); - await connection.RespondAsync(data, request.Id); + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] + var response = new JsonRpcResponse(data, request.Id); + + if(poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); } else @@ -78,7 +89,18 @@ protected virtual async Task OnSubscribeAsync(StratumConnection connection, Time "KaspaStratum/1.0.0", }; - await connection.RespondAsync(data, request.Id); + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(data, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); await connection.NotifyAsync(KaspaStratumMethods.SetExtraNonce, manager.GetSubscriberData(connection)); } @@ -112,13 +134,13 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time var workerName = split?.Skip(1).FirstOrDefault()?.Trim() ?? string.Empty; // assumes that minerName is an address - var (kaspaAddressUtility, errorKaspaAddressUtility) = KaspaUtils.ValidateAddress(minerName, manager.Network, coin.Symbol); + var (kaspaAddressUtility, errorKaspaAddressUtility) = KaspaUtils.ValidateAddress(minerName, manager.Network, coin); if (errorKaspaAddressUtility != null) - logger.Warn(() => $"[{connection.ConnectionId}] Unauthorized worker: {errorKaspaAddressUtility}"); + logger.Warn(() => $"[{connection.ConnectionId}]{(!string.IsNullOrEmpty(context.UserAgent) ? $"[{context.UserAgent}]" : string.Empty)} Unauthorized worker: {errorKaspaAddressUtility}"); else { context.IsAuthorized = true; - logger.Info(() => $"[{connection.ConnectionId}] worker: {minerName} => {KaspaConstants.KaspaAddressType[kaspaAddressUtility.KaspaAddress.Version()]}"); + logger.Info(() => $"[{connection.ConnectionId}]{(!string.IsNullOrEmpty(context.UserAgent) ? $"[{context.UserAgent}]" : string.Empty)} worker: {minerName} => {KaspaConstants.KaspaAddressType[kaspaAddressUtility.KaspaAddress.Version()]}"); } context.Miner = minerName; @@ -126,15 +148,25 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time if(context.IsAuthorized) { + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(context.IsAuthorized, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + // respond - await connection.RespondAsync(context.IsAuthorized, request.Id); + await connection.RespondAsync(response); // log association logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); // extract control vars from password var staticDiff = GetStaticDiffFromPassparts(passParts); - var startDiff = GetStartDiffFromPassparts(passParts); // Nicehash support var nicehashDiff = await GetNicehashStaticMinDiff(context, coin.Name, coin.GetAlgorithmName()); @@ -152,40 +184,29 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using miner supplied difficulty of {staticDiff.Value}"); } - // Start diff - if(startDiff.HasValue) - { - if(context.VarDiff != null && startDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && startDiff.Value > context.Difficulty) - { - context.SetDifficulty(startDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {startDiff.Value}"); - } - else - { - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {context.VarDiff.Config.MinDiff}"); - } - } - - // Static diff - if(staticDiff.HasValue && !startDiff.HasValue) - { - if(context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty) - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(staticDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); - } - else - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {context.VarDiff.Config.MinDiff}"); - } - } - - // send intial job - await SendJob(connection, context, currentJobParams); + // Static diff + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) + { + // There are several reports of IDIOTS mining with ridiculous amount of hashrate and maliciously using a very low staticDiff in order to attack mining pools. + // StaticDiff is now disabled by default for the KASPA family. Use it at your own risks. + if(extraPoolConfig.EnableStaticDifficulty) + context.VarDiff = null; // disable vardiff + + context.SetDifficulty(staticDiff.Value); + + if(extraPoolConfig.EnableStaticDifficulty) + logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); + else + logger.Warn(() => $"[{connection.ConnectionId}] Requesting static difficulty of {staticDiff.Value} (Request has been ignored and instead used as 'initial difficulty' for varDiff)"); + } + + var minerJobParams = CreateWorkerJob(connection); + + // send intial update + await connection.NotifyAsync(KaspaStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + await SendJob(connection, context, minerJobParams); } else @@ -204,6 +225,21 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time } } + private object[] CreateWorkerJob(StratumConnection connection) + { + var context = connection.ContextAs(); + var maxActiveJobs = extraPoolConfig?.MaxActiveJobs ?? 8; + var job = manager.GetJobForStratum(); + + // update context + lock(context) + { + context.AddJob(job, maxActiveJobs); + } + + return job.GetJobParams(); + } + protected virtual async Task OnSubmitAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) { var request = tsRequest.Value; @@ -236,7 +272,19 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta // submit var share = await manager.SubmitShareAsync(connection, requestParams, ct); - await connection.RespondAsync(true, request.Id); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // publish messageBus.SendMessage(share); @@ -244,7 +292,7 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta // telemetry PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, true); - logger.Info(() => $"[{connection.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty * KaspaConstants.ShareMultiplier, 3)}"); + logger.Info(() => $"[{connection.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty * coin.ShareMultiplier, 3)}"); // update pool stats if(share.IsBlockCandidate) @@ -281,8 +329,14 @@ protected virtual async Task OnNewJobAsync(object[] jobParams) await Guard(() => ForEachMinerAsync(async (connection, ct) => { var context = connection.ContextAs(); - - await SendJob(connection, context, currentJobParams); + + var minerJobParams = CreateWorkerJob(connection); + + // varDiff: if the client has a pending difficulty change, apply it now + if(context.ApplyPendingDifficulty()) + await connection.NotifyAsync(KaspaStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + + await SendJob(connection, context, minerJobParams); })); } @@ -304,9 +358,6 @@ private async Task SendJob(StratumConnection connection, KaspaWorkerContext cont jobParams[3], }; } - - // send difficulty - await connection.NotifyAsync(KaspaStratumMethods.SetDifficulty, new object[] { context.Difficulty }); // send job await connection.NotifyAsync(KaspaStratumMethods.MiningNotify, jobParamsActual); @@ -314,13 +365,13 @@ private async Task SendJob(StratumConnection connection, KaspaWorkerContext cont public override double HashrateFromShares(double shares, double interval) { - var multiplier = KaspaConstants.Pow2xDiff1TargetNumZero * (double) KaspaConstants.MinHash; + var multiplier = coin.HashrateMultiplier; var result = shares * multiplier / interval; return result; } - public override double ShareMultiplier => KaspaConstants.ShareMultiplier; + public override double ShareMultiplier => coin.ShareMultiplier; #region Overrides @@ -444,8 +495,11 @@ protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, if(context.ApplyPendingDifficulty()) { - // send job - await SendJob(connection, context, currentJobParams); + var minerJobParams = CreateWorkerJob(connection); + + // send varDiff update + await connection.NotifyAsync(KaspaStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + await SendJob(connection, context, minerJobParams); } } diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaUtils.cs b/src/Miningcore/Blockchain/Kaspa/KaspaUtils.cs index 2ec751d34b..b08fb382e8 100644 --- a/src/Miningcore/Blockchain/Kaspa/KaspaUtils.cs +++ b/src/Miningcore/Blockchain/Kaspa/KaspaUtils.cs @@ -6,6 +6,8 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using Miningcore.Configuration; +using Miningcore.Contracts; using Miningcore.Crypto; using Miningcore.Crypto.Hashing.Algorithms; using Miningcore.Util; @@ -15,8 +17,10 @@ namespace Miningcore.Blockchain.Kaspa; public static class KaspaUtils { - public static (KaspaAddressUtility, Exception) ValidateAddress(string address, string network, string coinSymbol = "KAS") + public static (KaspaAddressUtility, Exception) ValidateAddress(string address, string network, KaspaCoinTemplate coin) { + Contract.RequiresNonNull(coin); + if(string.IsNullOrEmpty(address)) return (null, new ArgumentException($"Empty address...")); @@ -44,7 +48,7 @@ public static (KaspaAddressUtility, Exception) ValidateAddress(string address, s try { - var kaspaAddressUtility = new KaspaAddressUtility(coinSymbol); + var kaspaAddressUtility = new KaspaAddressUtility(coin); kaspaAddressUtility.DecodeAddress(address, networkBech32Prefix); return (kaspaAddressUtility, null); @@ -57,7 +61,7 @@ public static (KaspaAddressUtility, Exception) ValidateAddress(string address, s public static BigInteger DifficultyToTarget(double difficulty) { - return BigInteger.Divide(KaspaConstants.Diff1Target, new BigInteger(difficulty)); + return (BigInteger) BigRational.Divide(new BigRational(KaspaConstants.Diff1Target), new BigRational(difficulty)); } public static BigInteger CalculateTarget(uint bits) @@ -89,12 +93,7 @@ public static BigInteger CalculateTarget(uint bits) public static double TargetToDifficulty(BigInteger target) { - return (double) new BigRational(KaspaConstants.Diff1Target, target); - } - - public static double DifficultyToHashrate(double diff) - { - return (double) new BigRational(BigInteger.Multiply(BigInteger.Multiply(KaspaConstants.MinHash, KaspaConstants.BigGig), new BigInteger(diff)), KaspaConstants.Diff1); + return (double) BigRational.Divide(new BigRational(KaspaConstants.Diff1Target), new BigRational(target)); } public static double BigDiffToLittle(BigInteger diff) @@ -174,16 +173,6 @@ public static uint BigToCompact(BigInteger n) return compact; } - public static double CalcWork(uint bits) - { - BigInteger difficultyNum = CompactToBig(bits); - - if (difficultyNum.Sign <= 0) - return (double) BigInteger.Zero; - - return (double) new BigRational(KaspaConstants.OneLsh256, BigInteger.Add(difficultyNum, KaspaConstants.BigOne)); - } - public static byte[] HashBlake2b(byte[] serializedScript) { IHashAlgorithm scriptHasher = new Blake2b(); @@ -345,136 +334,24 @@ public override string ToString() public class KaspaAddressUtility { public KaspaIAddress KaspaAddress { get; private set; } - public string CoinSymbol { get; private set; } + public KaspaCoinTemplate coin { get; private set; } + + private Dictionary stringsToBech32Prefixes; - public KaspaAddressUtility(string coinSymbol = "KAS") + public KaspaAddressUtility(KaspaCoinTemplate coin) { - this.CoinSymbol = coinSymbol; - - // Build address pattern based on network type and coin symbol - switch(this.CoinSymbol) - { - case "PUG": - this.stringsToBech32Prefixes = new Dictionary - { - { PugdagConstants.ChainPrefixMainnet, KaspaBech32Prefix.KaspaMain }, - { PugdagConstants.ChainPrefixDevnet, KaspaBech32Prefix.KaspaDev }, - { PugdagConstants.ChainPrefixTestnet, KaspaBech32Prefix.KaspaTest }, - { PugdagConstants.ChainPrefixSimnet, KaspaBech32Prefix.KaspaSim }, - }; - - break; - case "CSS": - this.stringsToBech32Prefixes = new Dictionary - { - { ConsensusConstants.ChainPrefixMainnet, KaspaBech32Prefix.KaspaMain }, - { ConsensusConstants.ChainPrefixDevnet, KaspaBech32Prefix.KaspaDev }, - { ConsensusConstants.ChainPrefixTestnet, KaspaBech32Prefix.KaspaTest }, - { ConsensusConstants.ChainPrefixSimnet, KaspaBech32Prefix.KaspaSim }, - }; - - break; - case "BGA": - this.stringsToBech32Prefixes = new Dictionary - { - { BugnaConstants.ChainPrefixMainnet, KaspaBech32Prefix.KaspaMain }, - { BugnaConstants.ChainPrefixDevnet, KaspaBech32Prefix.KaspaDev }, - { BugnaConstants.ChainPrefixTestnet, KaspaBech32Prefix.KaspaTest }, - { BugnaConstants.ChainPrefixSimnet, KaspaBech32Prefix.KaspaSim }, - }; - - break; - case "CAS": - this.stringsToBech32Prefixes = new Dictionary - { - { KaspaClassicConstants.ChainPrefixMainnet, KaspaBech32Prefix.KaspaMain }, - { KaspaClassicConstants.ChainPrefixDevnet, KaspaBech32Prefix.KaspaDev }, - { KaspaClassicConstants.ChainPrefixTestnet, KaspaBech32Prefix.KaspaTest }, - { KaspaClassicConstants.ChainPrefixSimnet, KaspaBech32Prefix.KaspaSim }, - }; - - break; - case "HTN": - this.stringsToBech32Prefixes = new Dictionary - { - { HoosatConstants.ChainPrefixMainnet, KaspaBech32Prefix.KaspaMain }, - { HoosatConstants.ChainPrefixDevnet, KaspaBech32Prefix.KaspaDev }, - { HoosatConstants.ChainPrefixTestnet, KaspaBech32Prefix.KaspaTest }, - { HoosatConstants.ChainPrefixSimnet, KaspaBech32Prefix.KaspaSim }, - }; + Contract.RequiresNonNull(coin); - break; - case "KODA": - this.stringsToBech32Prefixes = new Dictionary - { - { KobradagConstants.ChainPrefixMainnet, KaspaBech32Prefix.KaspaMain }, - { KobradagConstants.ChainPrefixDevnet, KaspaBech32Prefix.KaspaDev }, - { KobradagConstants.ChainPrefixTestnet, KaspaBech32Prefix.KaspaTest }, - { KobradagConstants.ChainPrefixSimnet, KaspaBech32Prefix.KaspaSim }, - }; - - break; - case "KLS": - this.stringsToBech32Prefixes = new Dictionary - { - { KarlsencoinConstants.ChainPrefixMainnet, KaspaBech32Prefix.KaspaMain }, - { KarlsencoinConstants.ChainPrefixDevnet, KaspaBech32Prefix.KaspaDev }, - { KarlsencoinConstants.ChainPrefixTestnet, KaspaBech32Prefix.KaspaTest }, - { KarlsencoinConstants.ChainPrefixSimnet, KaspaBech32Prefix.KaspaSim }, - }; - - break; - case "NTL": - this.stringsToBech32Prefixes = new Dictionary - { - { NautilusConstants.ChainPrefixMainnet, KaspaBech32Prefix.KaspaMain }, - { NautilusConstants.ChainPrefixDevnet, KaspaBech32Prefix.KaspaDev }, - { NautilusConstants.ChainPrefixTestnet, KaspaBech32Prefix.KaspaTest }, - { NautilusConstants.ChainPrefixSimnet, KaspaBech32Prefix.KaspaSim }, - }; - - break; - case "NXL": - this.stringsToBech32Prefixes = new Dictionary - { - { NexelliaConstants.ChainPrefixMainnet, KaspaBech32Prefix.KaspaMain }, - { NexelliaConstants.ChainPrefixDevnet, KaspaBech32Prefix.KaspaDev }, - { NexelliaConstants.ChainPrefixTestnet, KaspaBech32Prefix.KaspaTest }, - { NexelliaConstants.ChainPrefixSimnet, KaspaBech32Prefix.KaspaSim }, - }; - - break; - case "PYI": - this.stringsToBech32Prefixes = new Dictionary - { - { PyrinConstants.ChainPrefixMainnet, KaspaBech32Prefix.KaspaMain }, - { PyrinConstants.ChainPrefixDevnet, KaspaBech32Prefix.KaspaDev }, - { PyrinConstants.ChainPrefixTestnet, KaspaBech32Prefix.KaspaTest }, - { PyrinConstants.ChainPrefixSimnet, KaspaBech32Prefix.KaspaSim }, - }; - - break; - case "SDR": - this.stringsToBech32Prefixes = new Dictionary - { - { SedraCoinConstants.ChainPrefixMainnet, KaspaBech32Prefix.KaspaMain }, - { SedraCoinConstants.ChainPrefixDevnet, KaspaBech32Prefix.KaspaDev }, - { SedraCoinConstants.ChainPrefixTestnet, KaspaBech32Prefix.KaspaTest }, - { SedraCoinConstants.ChainPrefixSimnet, KaspaBech32Prefix.KaspaSim }, - }; + this.coin = coin; - break; - default: - this.stringsToBech32Prefixes = new Dictionary - { - { KaspaConstants.ChainPrefixMainnet, KaspaBech32Prefix.KaspaMain }, - { KaspaConstants.ChainPrefixDevnet, KaspaBech32Prefix.KaspaDev }, - { KaspaConstants.ChainPrefixTestnet, KaspaBech32Prefix.KaspaTest }, - { KaspaConstants.ChainPrefixSimnet, KaspaBech32Prefix.KaspaSim }, - }; - - break; - } + // Build address pattern based on network type and KaspaCoinTemplate + this.stringsToBech32Prefixes = new Dictionary + { + { this.coin.AddressBech32Prefix, KaspaBech32Prefix.KaspaMain }, + { this.coin.AddressBech32PrefixDevnet, KaspaBech32Prefix.KaspaDev }, + { this.coin.AddressBech32PrefixSimnet, KaspaBech32Prefix.KaspaSim }, + { this.coin.AddressBech32PrefixTestnet, KaspaBech32Prefix.KaspaTest } + }; } public string EncodeAddress(KaspaBech32Prefix prefix, byte[] payload, byte version) @@ -529,8 +406,6 @@ public string PrefixToString(KaspaBech32Prefix prefix) return string.Empty; } - - private Dictionary stringsToBech32Prefixes; } public static class KaspaBech32 diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaWorkerContext.cs b/src/Miningcore/Blockchain/Kaspa/KaspaWorkerContext.cs index 4dbeee5959..95f47199f5 100644 --- a/src/Miningcore/Blockchain/Kaspa/KaspaWorkerContext.cs +++ b/src/Miningcore/Blockchain/Kaspa/KaspaWorkerContext.cs @@ -1,3 +1,6 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; using Miningcore.Mining; namespace Miningcore.Blockchain.Kaspa; @@ -7,12 +10,12 @@ public class KaspaWorkerContext : WorkerContextBase /// /// Usually a wallet address /// - public string Miner { get; set; } + public override string Miner { get; set; } /// /// Arbitrary worker identififer for miners using multiple rigs /// - public string Worker { get; set; } + public override string Worker { get; set; } /// /// Unique value assigned per worker @@ -24,4 +27,23 @@ public class KaspaWorkerContext : WorkerContextBase /// Default: false /// public bool IsLargeJob { get; set; } = false; + + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); + + public virtual void AddJob(KaspaJob job, int maxActiveJobs) + { + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); + + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); + } + + public KaspaJob GetJob(string jobId) + { + return validJobs.ToArray().FirstOrDefault(x => x.JobId == jobId); + } } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/KaspaWalletd.cs b/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/KaspaWalletd.cs index db044a7bc3..13aa683898 100644 --- a/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/KaspaWalletd.cs +++ b/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/KaspaWalletd.cs @@ -78,14 +78,31 @@ static KaspawalletdReflection() { "Lkthc3BhV2FsbGV0ZC5TZW5kUmVzcG9uc2UiABI/CgRTaWduEhkuS2FzcGFX", "YWxsZXRkLlNpZ25SZXF1ZXN0GhouS2FzcGFXYWxsZXRkLlNpZ25SZXNwb25z", "ZSIAQiuqAihNaW5pbmdjb3JlLkJsb2NrY2hhaW4uS2FzcGEuS2FzcGFXYWxs", - "ZXRkYgZwcm90bzM=")); + "ZXN0GiMua2FzcGF3YWxsZXRkLlNob3dBZGRyZXNzZXNSZXNwb25zZSIAElEK", + "Ck5ld0FkZHJlc3MSHy5rYXNwYXdhbGxldGQuTmV3QWRkcmVzc1JlcXVlc3Qa", + "IC5rYXNwYXdhbGxldGQuTmV3QWRkcmVzc1Jlc3BvbnNlIgASSwoIU2h1dGRv", + "d24SHS5rYXNwYXdhbGxldGQuU2h1dGRvd25SZXF1ZXN0Gh4ua2FzcGF3YWxs", + "ZXRkLlNodXRkb3duUmVzcG9uc2UiABJOCglCcm9hZGNhc3QSHi5rYXNwYXdh", + "bGxldGQuQnJvYWRjYXN0UmVxdWVzdBofLmthc3Bhd2FsbGV0ZC5Ccm9hZGNh", + "c3RSZXNwb25zZSIAElkKFEJyb2FkY2FzdFJlcGxhY2VtZW50Eh4ua2FzcGF3", + "YWxsZXRkLkJyb2FkY2FzdFJlcXVlc3QaHy5rYXNwYXdhbGxldGQuQnJvYWRj", + "YXN0UmVzcG9uc2UiABI/CgRTZW5kEhkua2FzcGF3YWxsZXRkLlNlbmRSZXF1", + "ZXN0Ghoua2FzcGF3YWxsZXRkLlNlbmRSZXNwb25zZSIAEj8KBFNpZ24SGS5r", + "YXNwYXdhbGxldGQuU2lnblJlcXVlc3QaGi5rYXNwYXdhbGxldGQuU2lnblJl", + "c3BvbnNlIgASUQoKR2V0VmVyc2lvbhIfLmthc3Bhd2FsbGV0ZC5HZXRWZXJz", + "aW9uUmVxdWVzdBogLmthc3Bhd2FsbGV0ZC5HZXRWZXJzaW9uUmVzcG9uc2Ui", + "ABJICgdCdW1wRmVlEhwua2FzcGF3YWxsZXRkLkJ1bXBGZWVSZXF1ZXN0Gh0u", + "a2FzcGF3YWxsZXRkLkJ1bXBGZWVSZXNwb25zZSIAQltaNGdpdGh1Yi5jb20v", + "a2FzcGFuZXQva2FzcGFkL2NtZC9rYXNwYXdhbGxldC9kYWVtb24vcGKqAiJH", + "cnBjR3JlZXRlckNsaWVudC5SUEMuS2FzcGFXYWxsZXRkYgZwcm90bzM=")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetBalanceRequest), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetBalanceRequest.Parser, null, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetBalanceResponse), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetBalanceResponse.Parser, new[]{ "Available", "Pending", "AddressBalances" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.AddressBalances), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.AddressBalances.Parser, new[]{ "Address", "Available", "Pending" }, null, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.CreateUnsignedTransactionsRequest), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.CreateUnsignedTransactionsRequest.Parser, new[]{ "Address", "Amount", "From", "UseExistingChangeAddress", "IsSendAll" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.FeePolicy), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.FeePolicy.Parser, new[]{ "MaxFeeRate", "ExactFeeRate", "MaxFee" }, new[]{ "FeePolicy" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.CreateUnsignedTransactionsRequest), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.CreateUnsignedTransactionsRequest.Parser, new[]{ "Address", "Amount", "From", "UseExistingChangeAddress", "IsSendAll", "FeePolicy" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.CreateUnsignedTransactionsResponse), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.CreateUnsignedTransactionsResponse.Parser, new[]{ "UnsignedTransactions" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShowAddressesRequest), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShowAddressesRequest.Parser, null, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShowAddressesResponse), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShowAddressesResponse.Parser, new[]{ "Address" }, null, null, null, null), @@ -101,10 +118,14 @@ static KaspawalletdReflection() { new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.UtxoEntry), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.UtxoEntry.Parser, new[]{ "Amount", "ScriptPublicKey", "BlockDaaScore", "IsCoinbase" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetExternalSpendableUTXOsRequest), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetExternalSpendableUTXOsRequest.Parser, new[]{ "Address" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetExternalSpendableUTXOsResponse), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetExternalSpendableUTXOsResponse.Parser, new[]{ "Entries" }, null, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SendRequest), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SendRequest.Parser, new[]{ "ToAddress", "Amount", "Password", "From", "UseExistingChangeAddress", "IsSendAll" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SendRequest), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SendRequest.Parser, new[]{ "ToAddress", "Amount", "Password", "From", "UseExistingChangeAddress", "IsSendAll", "FeePolicy" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SendResponse), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SendResponse.Parser, new[]{ "TxIDs", "SignedTransactions" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SignRequest), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SignRequest.Parser, new[]{ "UnsignedTransactions", "Password" }, null, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SignResponse), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SignResponse.Parser, new[]{ "SignedTransactions" }, null, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SignResponse), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SignResponse.Parser, new[]{ "SignedTransactions" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetVersionRequest), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetVersionRequest.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetVersionResponse), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetVersionResponse.Parser, new[]{ "Version" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BumpFeeRequest), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BumpFeeRequest.Parser, new[]{ "Password", "From", "UseExistingChangeAddress", "FeePolicy", "TxID" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BumpFeeResponse), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BumpFeeResponse.Parser, new[]{ "Transactions", "TxIDs" }, null, null, null, null) })); } #endregion @@ -574,6 +595,267 @@ public void MergeFrom(pb::CodedInputStream input) { } + public sealed partial class FeePolicy : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new FeePolicy()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::Miningcore.Blockchain.Kaspa.KaspaWalletd.KaspawalletdReflection.Descriptor.MessageTypes[3]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public FeePolicy() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public FeePolicy(FeePolicy other) : this() { + switch (other.FeePolicyCase) { + case FeePolicyOneofCase.MaxFeeRate: + MaxFeeRate = other.MaxFeeRate; + break; + case FeePolicyOneofCase.ExactFeeRate: + ExactFeeRate = other.ExactFeeRate; + break; + case FeePolicyOneofCase.MaxFee: + MaxFee = other.MaxFee; + break; + } + + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public FeePolicy Clone() { + return new FeePolicy(this); + } + + /// Field number for the "maxFeeRate" field. + public const int MaxFeeRateFieldNumber = 6; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public double MaxFeeRate { + get { return HasMaxFeeRate ? (double) feePolicy_ : 0D; } + set { + feePolicy_ = value; + feePolicyCase_ = FeePolicyOneofCase.MaxFeeRate; + } + } + + /// Gets whether the "maxFeeRate" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool HasMaxFeeRate { + get { return feePolicyCase_ == FeePolicyOneofCase.MaxFeeRate; } + } + + /// Clears the value of the oneof if it's currently set to "maxFeeRate" + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void ClearMaxFeeRate() { + if (HasMaxFeeRate) { + ClearFeePolicy(); + } + } + + /// Field number for the "exactFeeRate" field. + public const int ExactFeeRateFieldNumber = 7; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public double ExactFeeRate { + get { return HasExactFeeRate ? (double) feePolicy_ : 0D; } + set { + feePolicy_ = value; + feePolicyCase_ = FeePolicyOneofCase.ExactFeeRate; + } + } + + /// Gets whether the "exactFeeRate" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool HasExactFeeRate { + get { return feePolicyCase_ == FeePolicyOneofCase.ExactFeeRate; } + } + + /// Clears the value of the oneof if it's currently set to "exactFeeRate" + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void ClearExactFeeRate() { + if (HasExactFeeRate) { + ClearFeePolicy(); + } + } + + /// Field number for the "maxFee" field. + public const int MaxFeeFieldNumber = 8; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong MaxFee { + get { return HasMaxFee ? (ulong) feePolicy_ : 0UL; } + set { + feePolicy_ = value; + feePolicyCase_ = FeePolicyOneofCase.MaxFee; + } + } + + /// Gets whether the "maxFee" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool HasMaxFee { + get { return feePolicyCase_ == FeePolicyOneofCase.MaxFee; } + } + + /// Clears the value of the oneof if it's currently set to "maxFee" + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void ClearMaxFee() { + if (HasMaxFee) { + ClearFeePolicy(); + } + } + + private object feePolicy_; + /// Enum of possible cases for the "feePolicy" oneof. + public enum FeePolicyOneofCase { + None = 0, + MaxFeeRate = 6, + ExactFeeRate = 7, + MaxFee = 8, + } + private FeePolicyOneofCase feePolicyCase_ = FeePolicyOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public FeePolicyOneofCase FeePolicyCase { + get { return feePolicyCase_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void ClearFeePolicy() { + feePolicyCase_ = FeePolicyOneofCase.None; + feePolicy_ = null; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as FeePolicy); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(FeePolicy other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals(MaxFeeRate, other.MaxFeeRate)) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals(ExactFeeRate, other.ExactFeeRate)) return false; + if (MaxFee != other.MaxFee) return false; + if (FeePolicyCase != other.FeePolicyCase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (HasMaxFeeRate) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(MaxFeeRate); + if (HasExactFeeRate) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(ExactFeeRate); + if (HasMaxFee) hash ^= MaxFee.GetHashCode(); + hash ^= (int) feePolicyCase_; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (HasMaxFeeRate) { + output.WriteRawTag(49); + output.WriteDouble(MaxFeeRate); + } + if (HasExactFeeRate) { + output.WriteRawTag(57); + output.WriteDouble(ExactFeeRate); + } + if (HasMaxFee) { + output.WriteRawTag(64); + output.WriteUInt64(MaxFee); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (HasMaxFeeRate) { + size += 1 + 8; + } + if (HasExactFeeRate) { + size += 1 + 8; + } + if (HasMaxFee) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(MaxFee); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(FeePolicy other) { + if (other == null) { + return; + } + switch (other.FeePolicyCase) { + case FeePolicyOneofCase.MaxFeeRate: + MaxFeeRate = other.MaxFeeRate; + break; + case FeePolicyOneofCase.ExactFeeRate: + ExactFeeRate = other.ExactFeeRate; + break; + case FeePolicyOneofCase.MaxFee: + MaxFee = other.MaxFee; + break; + } + + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 49: { + MaxFeeRate = input.ReadDouble(); + break; + } + case 57: { + ExactFeeRate = input.ReadDouble(); + break; + } + case 64: { + MaxFee = input.ReadUInt64(); + break; + } + } + } + } + + } + public sealed partial class CreateUnsignedTransactionsRequest : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateUnsignedTransactionsRequest()); private pb::UnknownFieldSet _unknownFields; @@ -604,6 +886,7 @@ public CreateUnsignedTransactionsRequest(CreateUnsignedTransactionsRequest other from_ = other.from_.Clone(); useExistingChangeAddress_ = other.useExistingChangeAddress_; isSendAll_ = other.isSendAll_; + feePolicy_ = other.feePolicy_ != null ? other.feePolicy_.Clone() : null; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } @@ -666,6 +949,17 @@ public bool IsSendAll { } } + /// Field number for the "feePolicy" field. + public const int FeePolicyFieldNumber = 6; + private global::Miningcore.Blockchain.Kaspa.KaspaWalletd.FeePolicy feePolicy_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.KaspaWalletd.FeePolicy FeePolicy { + get { return feePolicy_; } + set { + feePolicy_ = value; + } + } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as CreateUnsignedTransactionsRequest); @@ -684,6 +978,7 @@ public bool Equals(CreateUnsignedTransactionsRequest other) { if(!from_.Equals(other.from_)) return false; if (UseExistingChangeAddress != other.UseExistingChangeAddress) return false; if (IsSendAll != other.IsSendAll) return false; + if (!object.Equals(FeePolicy, other.FeePolicy)) return false; return Equals(_unknownFields, other._unknownFields); } @@ -695,6 +990,7 @@ public override int GetHashCode() { hash ^= from_.GetHashCode(); if (UseExistingChangeAddress != false) hash ^= UseExistingChangeAddress.GetHashCode(); if (IsSendAll != false) hash ^= IsSendAll.GetHashCode(); + if (feePolicy_ != null) hash ^= FeePolicy.GetHashCode(); if (_unknownFields != null) { hash ^= _unknownFields.GetHashCode(); } @@ -725,6 +1021,10 @@ public void WriteTo(pb::CodedOutputStream output) { output.WriteRawTag(40); output.WriteBool(IsSendAll); } + if (feePolicy_ != null) { + output.WriteRawTag(50); + output.WriteMessage(FeePolicy); + } if (_unknownFields != null) { _unknownFields.WriteTo(output); } @@ -746,6 +1046,9 @@ public int CalculateSize() { if (IsSendAll != false) { size += 1 + 1; } + if (feePolicy_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(FeePolicy); + } if (_unknownFields != null) { size += _unknownFields.CalculateSize(); } @@ -770,6 +1073,12 @@ public void MergeFrom(CreateUnsignedTransactionsRequest other) { if (other.IsSendAll != false) { IsSendAll = other.IsSendAll; } + if (other.feePolicy_ != null) { + if (feePolicy_ == null) { + FeePolicy = new global::Miningcore.Blockchain.Kaspa.KaspaWalletd.FeePolicy(); + } + FeePolicy.MergeFrom(other.FeePolicy); + } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); } @@ -801,6 +1110,13 @@ public void MergeFrom(pb::CodedInputStream input) { IsSendAll = input.ReadBool(); break; } + case 50: { + if (feePolicy_ == null) { + FeePolicy = new global::Miningcore.Blockchain.Kaspa.KaspaWalletd.FeePolicy(); + } + input.ReadMessage(FeePolicy); + break; + } } } } @@ -2866,6 +3182,7 @@ public SendRequest(SendRequest other) : this() { from_ = other.from_.Clone(); useExistingChangeAddress_ = other.useExistingChangeAddress_; isSendAll_ = other.isSendAll_; + feePolicy_ = other.feePolicy_ != null ? other.feePolicy_.Clone() : null; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } @@ -2939,6 +3256,17 @@ public bool IsSendAll { } } + /// Field number for the "feePolicy" field. + public const int FeePolicyFieldNumber = 7; + private global::Miningcore.Blockchain.Kaspa.KaspaWalletd.FeePolicy feePolicy_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.KaspaWalletd.FeePolicy FeePolicy { + get { return feePolicy_; } + set { + feePolicy_ = value; + } + } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as SendRequest); @@ -2958,6 +3286,7 @@ public bool Equals(SendRequest other) { if(!from_.Equals(other.from_)) return false; if (UseExistingChangeAddress != other.UseExistingChangeAddress) return false; if (IsSendAll != other.IsSendAll) return false; + if (!object.Equals(FeePolicy, other.FeePolicy)) return false; return Equals(_unknownFields, other._unknownFields); } @@ -2970,6 +3299,7 @@ public override int GetHashCode() { hash ^= from_.GetHashCode(); if (UseExistingChangeAddress != false) hash ^= UseExistingChangeAddress.GetHashCode(); if (IsSendAll != false) hash ^= IsSendAll.GetHashCode(); + if (feePolicy_ != null) hash ^= FeePolicy.GetHashCode(); if (_unknownFields != null) { hash ^= _unknownFields.GetHashCode(); } @@ -3004,6 +3334,10 @@ public void WriteTo(pb::CodedOutputStream output) { output.WriteRawTag(48); output.WriteBool(IsSendAll); } + if (feePolicy_ != null) { + output.WriteRawTag(58); + output.WriteMessage(FeePolicy); + } if (_unknownFields != null) { _unknownFields.WriteTo(output); } @@ -3028,6 +3362,9 @@ public int CalculateSize() { if (IsSendAll != false) { size += 1 + 1; } + if (feePolicy_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(FeePolicy); + } if (_unknownFields != null) { size += _unknownFields.CalculateSize(); } @@ -3055,6 +3392,12 @@ public void MergeFrom(SendRequest other) { if (other.IsSendAll != false) { IsSendAll = other.IsSendAll; } + if (other.feePolicy_ != null) { + if (feePolicy_ == null) { + FeePolicy = new global::Miningcore.Blockchain.Kaspa.KaspaWalletd.FeePolicy(); + } + FeePolicy.MergeFrom(other.FeePolicy); + } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); } @@ -3090,6 +3433,13 @@ public void MergeFrom(pb::CodedInputStream input) { IsSendAll = input.ReadBool(); break; } + case 58: { + if (feePolicy_ == null) { + FeePolicy = new global::Miningcore.Blockchain.Kaspa.KaspaWalletd.FeePolicy(); + } + input.ReadMessage(FeePolicy); + break; + } } } } @@ -3510,6 +3860,619 @@ public void MergeFrom(pb::CodedInputStream input) { } + public sealed partial class GetVersionRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetVersionRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::Miningcore.Blockchain.Kaspa.KaspaWalletd.KaspawalletdReflection.Descriptor.MessageTypes[24]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVersionRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVersionRequest(GetVersionRequest other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVersionRequest Clone() { + return new GetVersionRequest(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetVersionRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetVersionRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetVersionRequest other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class GetVersionResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetVersionResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::Miningcore.Blockchain.Kaspa.KaspaWalletd.KaspawalletdReflection.Descriptor.MessageTypes[25]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVersionResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVersionResponse(GetVersionResponse other) : this() { + version_ = other.version_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVersionResponse Clone() { + return new GetVersionResponse(this); + } + + /// Field number for the "version" field. + public const int VersionFieldNumber = 1; + private string version_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + + public string Version { + get { return version_; } + set { + version_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetVersionResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetVersionResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Version != other.Version) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Version.Length != 0) hash ^= Version.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Version.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Version); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Version.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Version); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetVersionResponse other) { + if (other == null) { + return; + } + if (other.Version.Length != 0) { + Version = other.Version; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Version = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class BumpFeeRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BumpFeeRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::Miningcore.Blockchain.Kaspa.KaspaWalletd.KaspawalletdReflection.Descriptor.MessageTypes[26]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BumpFeeRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BumpFeeRequest(BumpFeeRequest other) : this() { + password_ = other.password_; + from_ = other.from_.Clone(); + useExistingChangeAddress_ = other.useExistingChangeAddress_; + feePolicy_ = other.feePolicy_ != null ? other.feePolicy_.Clone() : null; + txID_ = other.txID_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BumpFeeRequest Clone() { + return new BumpFeeRequest(this); + } + + /// Field number for the "password" field. + public const int PasswordFieldNumber = 1; + private string password_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Password { + get { return password_; } + set { + password_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "from" field. + public const int FromFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_from_codec + = pb::FieldCodec.ForString(18); + private readonly pbc::RepeatedField from_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField From { + get { return from_; } + } + + /// Field number for the "useExistingChangeAddress" field. + public const int UseExistingChangeAddressFieldNumber = 3; + private bool useExistingChangeAddress_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool UseExistingChangeAddress { + get { return useExistingChangeAddress_; } + set { + useExistingChangeAddress_ = value; + } + } + + /// Field number for the "feePolicy" field. + public const int FeePolicyFieldNumber = 4; + private global::Miningcore.Blockchain.Kaspa.KaspaWalletd.FeePolicy feePolicy_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.KaspaWalletd.FeePolicy FeePolicy { + get { return feePolicy_; } + set { + feePolicy_ = value; + } + } + + /// Field number for the "txID" field. + public const int TxIDFieldNumber = 5; + private string txID_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string TxID { + get { return txID_; } + set { + txID_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BumpFeeRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + + public bool Equals(BumpFeeRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Password != other.Password) return false; + if(!from_.Equals(other.from_)) return false; + if (UseExistingChangeAddress != other.UseExistingChangeAddress) return false; + if (!object.Equals(FeePolicy, other.FeePolicy)) return false; + if (TxID != other.TxID) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Password.Length != 0) hash ^= Password.GetHashCode(); + hash ^= from_.GetHashCode(); + if (UseExistingChangeAddress != false) hash ^= UseExistingChangeAddress.GetHashCode(); + if (feePolicy_ != null) hash ^= FeePolicy.GetHashCode(); + if (TxID.Length != 0) hash ^= TxID.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Password.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Password); + } + from_.WriteTo(output, _repeated_from_codec); + if (UseExistingChangeAddress != false) { + output.WriteRawTag(24); + output.WriteBool(UseExistingChangeAddress); + } + if (feePolicy_ != null) { + output.WriteRawTag(34); + output.WriteMessage(FeePolicy); + } + if (TxID.Length != 0) { + output.WriteRawTag(42); + output.WriteString(TxID); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Password.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Password); + } + size += from_.CalculateSize(_repeated_from_codec); + if (UseExistingChangeAddress != false) { + size += 1 + 1; + } + if (feePolicy_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(FeePolicy); + } + if (TxID.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(TxID); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BumpFeeRequest other) { + if (other == null) { + return; + } + if (other.Password.Length != 0) { + Password = other.Password; + } + from_.Add(other.from_); + if (other.UseExistingChangeAddress != false) { + UseExistingChangeAddress = other.UseExistingChangeAddress; + } + if (other.feePolicy_ != null) { + if (feePolicy_ == null) { + FeePolicy = new global::Miningcore.Blockchain.Kaspa.KaspaWalletd.FeePolicy(); + } + FeePolicy.MergeFrom(other.FeePolicy); + } + if (other.TxID.Length != 0) { + TxID = other.TxID; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Password = input.ReadString(); + break; + } + case 18: { + from_.AddEntriesFrom(input, _repeated_from_codec); + break; + } + case 24: { + UseExistingChangeAddress = input.ReadBool(); + break; + } + case 34: { + if (feePolicy_ == null) { + FeePolicy = new global::Miningcore.Blockchain.Kaspa.KaspaWalletd.FeePolicy(); + } + input.ReadMessage(FeePolicy); + break; + } + case 42: { + TxID = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class BumpFeeResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BumpFeeResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::Miningcore.Blockchain.Kaspa.KaspaWalletd.KaspawalletdReflection.Descriptor.MessageTypes[27]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BumpFeeResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BumpFeeResponse(BumpFeeResponse other) : this() { + transactions_ = other.transactions_.Clone(); + txIDs_ = other.txIDs_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BumpFeeResponse Clone() { + return new BumpFeeResponse(this); + } + + /// Field number for the "transactions" field. + public const int TransactionsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_transactions_codec + = pb::FieldCodec.ForBytes(10); + private readonly pbc::RepeatedField transactions_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Transactions { + get { return transactions_; } + } + + /// Field number for the "txIDs" field. + public const int TxIDsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_txIDs_codec + = pb::FieldCodec.ForString(18); + private readonly pbc::RepeatedField txIDs_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + + public pbc::RepeatedField TxIDs { + get { return txIDs_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BumpFeeResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BumpFeeResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!transactions_.Equals(other.transactions_)) return false; + if(!txIDs_.Equals(other.txIDs_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= transactions_.GetHashCode(); + hash ^= txIDs_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + transactions_.WriteTo(output, _repeated_transactions_codec); + txIDs_.WriteTo(output, _repeated_txIDs_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += transactions_.CalculateSize(_repeated_transactions_codec); + size += txIDs_.CalculateSize(_repeated_txIDs_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BumpFeeResponse other) { + if (other == null) { + return; + } + transactions_.Add(other.transactions_); + txIDs_.Add(other.txIDs_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + transactions_.AddEntriesFrom(input, _repeated_transactions_codec); + break; + } + case 18: { + txIDs_.AddEntriesFrom(input, _repeated_txIDs_codec); + break; + } + } + } + } + + } + #endregion } diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/KaspaWalletdGrpc.cs b/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/KaspaWalletdGrpc.cs index a477c24b83..ae893e3317 100644 --- a/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/KaspaWalletdGrpc.cs +++ b/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/KaspaWalletdGrpc.cs @@ -77,6 +77,20 @@ public KaspaWalletdRPC(string __ServiceName) "Sign", __Marshaller_KaspaWalletdRPC_SignRequest, __Marshaller_KaspaWalletdRPC_SignResponse); + + this.__Method_GetVersion = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetVersion", + __Marshaller_kaspawalletd_GetVersionRequest, + __Marshaller_kaspawalletd_GetVersionResponse); + + this.__Method_BumpFee = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "BumpFee", + __Marshaller_kaspawalletd_BumpFeeRequest, + __Marshaller_kaspawalletd_BumpFeeResponse); } [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] @@ -148,6 +162,14 @@ static T __Helper_DeserializeMessage(grpc::DeserializationContext context, gl static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_SignRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SignRequest.Parser)); [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_SignResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SignResponse.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_kaspawalletd_GetVersionRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetVersionRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_kaspawalletd_GetVersionResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetVersionResponse.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_kaspawalletd_BumpFeeRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BumpFeeRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_kaspawalletd_BumpFeeResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BumpFeeResponse.Parser)); [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] public grpc::Method __Method_GetBalance { get; private set; } @@ -176,6 +198,12 @@ static T __Helper_DeserializeMessage(grpc::DeserializationContext context, gl [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] public grpc::Method __Method_Sign { get; private set; } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public grpc::Method __Method_GetVersion { get; private set; } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public grpc::Method __Method_BumpFee { get; private set; } + /// Service descriptor public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor { @@ -448,6 +476,46 @@ protected KaspaWalletdRPCClient(ClientBaseConfiguration configuration) : base(co { return CallInvoker.AsyncUnaryCall(__KaspaWalletdRPC.__Method_Sign, null, options, request); } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetVersionResponse GetVersion(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetVersionRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetVersion(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetVersionResponse GetVersion(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetVersionRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__KaspaWalletdRPC.__Method_GetVersion, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall GetVersionAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetVersionRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetVersionAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall GetVersionAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetVersionRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__KaspaWalletdRPC.__Method_GetVersion, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BumpFeeResponse BumpFee(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BumpFeeRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return BumpFee(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BumpFeeResponse BumpFee(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BumpFeeRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__KaspaWalletdRPC.__Method_BumpFee, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall BumpFeeAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BumpFeeRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return BumpFeeAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall BumpFeeAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BumpFeeRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__KaspaWalletdRPC.__Method_BumpFee, null, options, request); + } /// Creates a new instance of client from given ClientBaseConfiguration. [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] protected override KaspaWalletdRPCClient NewInstance(ClientBaseConfiguration configuration) diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/kaspawalletd.proto b/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/kaspawalletd.proto index ca665aa6a5..5668871a51 100644 --- a/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/kaspawalletd.proto +++ b/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/kaspawalletd.proto @@ -15,6 +15,8 @@ service kaspawalletd { rpc Send(SendRequest) returns (SendResponse) {} // Since SignRequest contains a password - this command should only be used on a trusted or secure connection rpc Sign(SignRequest) returns (SignResponse) {} + rpc GetVersion(GetVersionRequest) returns (GetVersionResponse) {} + rpc BumpFee(BumpFeeRequest) returns (BumpFeeResponse) {} } message GetBalanceRequest { @@ -32,12 +34,21 @@ message AddressBalances { uint64 pending = 3; } +message FeePolicy { + oneof feePolicy { + double maxFeeRate = 6; + double exactFeeRate = 7; + uint64 maxFee = 8; + } +} + message CreateUnsignedTransactionsRequest { string address = 1; uint64 amount = 2; repeated string from = 3; bool useExistingChangeAddress = 4; bool isSendAll = 5; + FeePolicy feePolicy = 6; } message CreateUnsignedTransactionsResponse { @@ -111,6 +122,7 @@ message SendRequest{ repeated string from = 4; bool useExistingChangeAddress = 5; bool isSendAll = 6; + FeePolicy feePolicy = 7; } message SendResponse{ @@ -127,3 +139,20 @@ message SignRequest{ message SignResponse{ repeated bytes signedTransactions = 1; } + +message GetVersionRequest {} + +message GetVersionResponse { string version = 1; } + +message BumpFeeRequest { + string password = 1; + repeated string from = 2; + bool useExistingChangeAddress = 3; + FeePolicy feePolicy = 4; + string txID = 5; +} + +message BumpFeeResponse { + repeated bytes transactions = 1; + repeated string txIDs = 2; +} diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/P2P.cs b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/P2P.cs index c5adf4cdcc..c2ea71f6a2 100644 --- a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/P2P.cs +++ b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/P2P.cs @@ -145,7 +145,7 @@ static P2PReflection() { new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.AddressesMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.AddressesMessage.Parser, new[]{ "AddressList" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NetAddress), global::Miningcore.Blockchain.Kaspa.Kaspad.NetAddress.Parser, new[]{ "Timestamp", "Ip", "Port" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.SubnetworkId), global::Miningcore.Blockchain.Kaspa.Kaspad.SubnetworkId.Parser, new[]{ "Bytes" }, null, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionMessage.Parser, new[]{ "Version", "Inputs", "Outputs", "LockTime", "SubnetworkId", "Gas", "Payload" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionMessage.Parser, new[]{ "Version", "Inputs", "Outputs", "LockTime", "SubnetworkId", "Gas", "Payload", "Mass" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionInput), global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionInput.Parser, new[]{ "PreviousOutpoint", "SignatureScript", "Sequence", "SigOpCount" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.Outpoint), global::Miningcore.Blockchain.Kaspa.Kaspad.Outpoint.Parser, new[]{ "TransactionId", "Index" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionId), global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionId.Parser, new[]{ "Bytes" }, null, null, null, null), @@ -837,6 +837,7 @@ public TransactionMessage(TransactionMessage other) : this() { subnetworkId_ = other.subnetworkId_ != null ? other.subnetworkId_.Clone() : null; gas_ = other.gas_; payload_ = other.payload_; + mass_ = other.mass_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } @@ -920,6 +921,17 @@ public ulong Gas { } } + /// Field number for the "mass" field. + public const int MassFieldNumber = 9; + private ulong mass_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Mass { + get { return mass_; } + set { + mass_ = value; + } + } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as TransactionMessage); @@ -940,6 +952,7 @@ public bool Equals(TransactionMessage other) { if (!object.Equals(SubnetworkId, other.SubnetworkId)) return false; if (Gas != other.Gas) return false; if (Payload != other.Payload) return false; + if (Mass != other.Mass) return false; return Equals(_unknownFields, other._unknownFields); } @@ -953,6 +966,7 @@ public override int GetHashCode() { if (subnetworkId_ != null) hash ^= SubnetworkId.GetHashCode(); if (Gas != 0UL) hash ^= Gas.GetHashCode(); if (Payload.Length != 0) hash ^= Payload.GetHashCode(); + if (Mass != 0UL) hash ^= Mass.GetHashCode(); if (_unknownFields != null) { hash ^= _unknownFields.GetHashCode(); } @@ -988,6 +1002,10 @@ public void WriteTo(pb::CodedOutputStream output) { output.WriteRawTag(66); output.WriteBytes(Payload); } + if (Mass != 0UL) { + output.WriteRawTag(72); + output.WriteUInt64(Mass); + } if (_unknownFields != null) { _unknownFields.WriteTo(output); } @@ -1013,6 +1031,9 @@ public int CalculateSize() { if (Payload.Length != 0) { size += 1 + pb::CodedOutputStream.ComputeBytesSize(Payload); } + if (Mass != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Mass); + } if (_unknownFields != null) { size += _unknownFields.CalculateSize(); } @@ -1044,6 +1065,9 @@ public void MergeFrom(TransactionMessage other) { if (other.Payload.Length != 0) { Payload = other.Payload; } + if (other.Mass != 0UL) { + Mass = other.Mass; + } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); } @@ -1086,6 +1110,10 @@ public void MergeFrom(pb::CodedInputStream input) { Payload = input.ReadBytes(); break; } + case 72: { + Mass = input.ReadUInt64(); + break; + } } } } diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/Rpc.cs b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/Rpc.cs index 219093eed7..7f73fd7634 100644 --- a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/Rpc.cs +++ b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/Rpc.cs @@ -262,7 +262,7 @@ static RpcReflection() { new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockHeader), global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockHeader.Parser, new[]{ "Version", "Parents", "HashMerkleRoot", "AcceptedIdMerkleRoot", "UtxoCommitment", "Timestamp", "Bits", "Nonce", "DaaScore", "BlueWork", "PruningPoint", "BlueScore" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockLevelParents), global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockLevelParents.Parser, new[]{ "ParentHashes" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockVerboseData), global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockVerboseData.Parser, new[]{ "Hash", "Difficulty", "SelectedParentHash", "TransactionIds", "IsHeaderOnly", "BlueScore", "ChildrenHashes", "MergeSetBluesHashes", "MergeSetRedsHashes", "IsChainBlock" }, null, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransaction), global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransaction.Parser, new[]{ "Version", "Inputs", "Outputs", "LockTime", "SubnetworkId", "Gas", "Payload", "VerboseData" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransaction), global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransaction.Parser, new[]{ "Version", "Inputs", "Outputs", "LockTime", "SubnetworkId", "Gas", "Payload", "VerboseData", "Mass" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionInput), global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionInput.Parser, new[]{ "PreviousOutpoint", "SignatureScript", "Sequence", "SigOpCount", "VerboseData" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RpcScriptPublicKey), global::Miningcore.Blockchain.Kaspa.Kaspad.RpcScriptPublicKey.Parser, new[]{ "Version", "ScriptPublicKey" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionOutput), global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionOutput.Parser, new[]{ "Amount", "ScriptPublicKey", "VerboseData" }, null, null, null, null), @@ -1626,6 +1626,7 @@ public RpcTransaction(RpcTransaction other) : this() { gas_ = other.gas_; payload_ = other.payload_; verboseData_ = other.verboseData_ != null ? other.verboseData_.Clone() : null; + mass_ = other.mass_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } @@ -1720,6 +1721,17 @@ public string Payload { } } + /// Field number for the "mass" field. + public const int MassFieldNumber = 10; + private ulong mass_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Mass { + get { return mass_; } + set { + mass_ = value; + } + } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as RpcTransaction); @@ -1741,6 +1753,7 @@ public bool Equals(RpcTransaction other) { if (Gas != other.Gas) return false; if (Payload != other.Payload) return false; if (!object.Equals(VerboseData, other.VerboseData)) return false; + if (Mass != other.Mass) return false; return Equals(_unknownFields, other._unknownFields); } @@ -1755,6 +1768,7 @@ public override int GetHashCode() { if (Gas != 0UL) hash ^= Gas.GetHashCode(); if (Payload.Length != 0) hash ^= Payload.GetHashCode(); if (verboseData_ != null) hash ^= VerboseData.GetHashCode(); + if (Mass != 0UL) hash ^= Mass.GetHashCode(); if (_unknownFields != null) { hash ^= _unknownFields.GetHashCode(); } @@ -1794,6 +1808,10 @@ public void WriteTo(pb::CodedOutputStream output) { output.WriteRawTag(74); output.WriteMessage(VerboseData); } + if (Mass != 0UL) { + output.WriteRawTag(80); + output.WriteUInt64(Mass); + } if (_unknownFields != null) { _unknownFields.WriteTo(output); } @@ -1822,6 +1840,9 @@ public int CalculateSize() { if (verboseData_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(VerboseData); } + if (Mass != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Mass); + } if (_unknownFields != null) { size += _unknownFields.CalculateSize(); } @@ -1856,6 +1877,9 @@ public void MergeFrom(RpcTransaction other) { } VerboseData.MergeFrom(other.VerboseData); } + if (other.Mass != 0UL) { + Mass = other.Mass; + } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); } @@ -1902,6 +1926,10 @@ public void MergeFrom(pb::CodedInputStream input) { input.ReadMessage(VerboseData); break; } + case 80: { + Mass = input.ReadUInt64(); + break; + } } } } diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/p2p.proto b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/p2p.proto index 6527082d90..5f8bec520d 100644 --- a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/p2p.proto +++ b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/p2p.proto @@ -31,6 +31,7 @@ message TransactionMessage{ SubnetworkId subnetworkId = 5; uint64 gas = 6; bytes payload = 8; + uint64 mass = 9; } message TransactionInput{ diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/rpc.proto b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/rpc.proto index 91eeb6f5a7..67ca4a402d 100644 --- a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/rpc.proto +++ b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/rpc.proto @@ -67,6 +67,7 @@ message RpcTransaction { uint64 gas = 6; string payload = 8; RpcTransactionVerboseData verboseData = 9; + uint64 mass = 10; } message RpcTransactionInput { diff --git a/src/Miningcore/Blockchain/Nexa/NexaJob.cs b/src/Miningcore/Blockchain/Nexa/NexaJob.cs index a0beeba695..e76f6b324b 100644 --- a/src/Miningcore/Blockchain/Nexa/NexaJob.cs +++ b/src/Miningcore/Blockchain/Nexa/NexaJob.cs @@ -34,7 +34,7 @@ public class NexaJob protected virtual (Share Share, object submitParams) ProcessShareInternal( StratumConnection worker, string nonce, string extraNonce1) { - var context = worker.ContextAs(); + var context = worker.ContextAs(); var extraNonce1Bytes = extraNonce1.HexToByteArray(); var nonceBytes = nonce.HexToByteArray(); diff --git a/src/Miningcore/Blockchain/Nexa/NexaJobManager.cs b/src/Miningcore/Blockchain/Nexa/NexaJobManager.cs index b18926a9cc..a4df66f7a2 100644 --- a/src/Miningcore/Blockchain/Nexa/NexaJobManager.cs +++ b/src/Miningcore/Blockchain/Nexa/NexaJobManager.cs @@ -127,15 +127,6 @@ await GetMiningCandidateAsync(ct) : job.Init(miningCandidate, blockTemplate, NextJobId(), poolConfig, clock, ShareMultiplier, coin.HeaderHasherValue); - lock(jobLock) - { - validJobs.Insert(0, job); - - // trim active jobs - while(validJobs.Count > maxActiveJobs) - validJobs.RemoveAt(validJobs.Count - 1); - } - if(isNew) { if(via != null) @@ -184,6 +175,12 @@ protected override object GetJobParamsForStratum(bool isNew) return job?.GetJobParams(); } + public override NexaJob GetJobForStratum() + { + var job = currentJob; + return job; + } + #region API-Surface public override void Configure(PoolConfig pc, ClusterConfig cc) @@ -202,7 +199,7 @@ public object[] GetSubscriberData(StratumConnection worker) { Contract.RequiresNonNull(worker); - var context = worker.ContextAs(); + var context = worker.ContextAs(); // assign unique ExtraNonce1 to worker (miner) context.ExtraNonce1 = extraNonceProvider.Next(); @@ -226,7 +223,7 @@ public async ValueTask SubmitShareAsync(StratumConnection worker, object if(submission is not object[] submitParams) throw new StratumException(StratumError.Other, "invalid params"); - var context = worker.ContextAs(); + var context = worker.ContextAs(); var workerValue = (submitParams[0] as string)?.Trim(); var jobId = submitParams[1] as string; @@ -242,9 +239,9 @@ public async ValueTask SubmitShareAsync(StratumConnection worker, object NexaJob job; - lock(jobLock) + lock(context) { - job = validJobs.FirstOrDefault(x => x.JobId == jobId); + job = context.GetJob(jobId); } if(job == null) diff --git a/src/Miningcore/Blockchain/Nexa/NexaPool.cs b/src/Miningcore/Blockchain/Nexa/NexaPool.cs index 129c2a4bea..7699070733 100644 --- a/src/Miningcore/Blockchain/Nexa/NexaPool.cs +++ b/src/Miningcore/Blockchain/Nexa/NexaPool.cs @@ -48,7 +48,7 @@ protected virtual async Task OnSubscribeAsync(StratumConnection connection, Time if(request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); - var context = connection.ContextAs(); + var context = connection.ContextAs(); var requestParams = request.ParamsAs(); var data = new object[] @@ -62,7 +62,18 @@ protected virtual async Task OnSubscribeAsync(StratumConnection connection, Time .Concat(manager.GetSubscriberData(connection)) .ToArray(); - await connection.RespondAsync(data, request.Id); + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(data, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // setup worker context context.IsSubscribed = true; @@ -79,9 +90,11 @@ protected virtual async Task OnSubscribeAsync(StratumConnection connection, Time context.SetDifficulty(nicehashDiff.Value); } + var minerJobParams = CreateWorkerJob(connection, context.IsSubscribed); + // send intial update await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); - await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); } protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) @@ -91,7 +104,7 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time if(request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); - var context = connection.ContextAs(); + var context = connection.ContextAs(); var requestParams = request.ParamsAs(); var workerValue = requestParams?.Length > 0 ? requestParams[0] : null; var password = requestParams?.Length > 1 ? requestParams[1] : null; @@ -109,48 +122,38 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time if(context.IsAuthorized) { + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(context.IsAuthorized, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + // respond - await connection.RespondAsync(context.IsAuthorized, request.Id); + await connection.RespondAsync(response); // log association logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); // extract control vars from password var staticDiff = GetStaticDiffFromPassparts(passParts); - var startDiff = GetStartDiffFromPassparts(passParts); - - // Start diff - if(startDiff.HasValue) - { - if(context.VarDiff != null && startDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && startDiff.Value > context.Difficulty) - { - context.SetDifficulty(startDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {startDiff.Value}"); - } - else - { - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {context.VarDiff.Config.MinDiff}"); - } - } - - // Static diff - if(staticDiff.HasValue && !startDiff.HasValue) - { - if(context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty) - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(staticDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); - } - else - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {context.VarDiff.Config.MinDiff}"); - } - } - await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + + // Static diff + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) + { + context.VarDiff = null; // disable vardiff + context.SetDifficulty(staticDiff.Value); + + logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); + + await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + } } else @@ -169,10 +172,24 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time } } + private object CreateWorkerJob(StratumConnection connection, bool cleanJob) + { + var context = connection.ContextAs(); + var job = manager.GetJobForStratum(); + + // update context + lock(context) + { + context.AddJob(job, manager.maxActiveJobs); + } + + return job.GetJobParams(); + } + protected virtual async Task OnSubmitAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) { var request = tsRequest.Value; - var context = connection.ContextAs(); + var context = connection.ContextAs(); try { @@ -201,7 +218,19 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta // submit var share = await manager.SubmitShareAsync(connection, requestParams, ct); - await connection.RespondAsync(true, request.Id); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // publish messageBus.SendMessage(share); @@ -240,10 +269,21 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta private async Task OnSuggestDifficultyAsync(StratumConnection connection, Timestamped tsRequest) { var request = tsRequest.Value; - var context = connection.ContextAs(); + var context = connection.ContextAs(); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } // acknowledge - await connection.RespondAsync(true, request.Id); + await connection.RespondAsync(response); try { @@ -275,14 +315,15 @@ protected virtual async Task OnNewJobAsync(object jobParams) await Guard(() => ForEachMinerAsync(async (connection, ct) => { - var context = connection.ContextAs(); + var context = connection.ContextAs(); + var minerJobParams = CreateWorkerJob(connection, true); // varDiff: if the client has a pending difficulty change, apply it now if(context.ApplyPendingDifficulty()) await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); // send job - await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); })); } @@ -349,7 +390,7 @@ protected override async Task InitStatsAsync(CancellationToken ct) protected override WorkerContextBase CreateWorkerContext() { - return new BitcoinWorkerContext(); + return new NexaWorkerContext(); } protected override async Task OnRequestAsync(StratumConnection connection, @@ -378,7 +419,20 @@ protected override async Task OnRequestAsync(StratumConnection connection, break; case BitcoinStratumMethods.ExtraNonceSubscribe: - await connection.RespondAsync(true, request.Id); + var context = connection.ContextAs(); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); break; default: @@ -401,8 +455,10 @@ protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, if(connection.Context.ApplyPendingDifficulty()) { + var minerJobParams = CreateWorkerJob(connection, true); + await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { connection.Context.Difficulty }); - await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); } } diff --git a/src/Miningcore/Blockchain/Nexa/NexaWorkerContext.cs b/src/Miningcore/Blockchain/Nexa/NexaWorkerContext.cs new file mode 100644 index 0000000000..b901aea2b5 --- /dev/null +++ b/src/Miningcore/Blockchain/Nexa/NexaWorkerContext.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; +using Miningcore.Mining; + +namespace Miningcore.Blockchain.Nexa; + +public class NexaWorkerContext : WorkerContextBase +{ + /// + /// Usually a wallet address + /// + public override string Miner { get; set; } + + /// + /// Arbitrary worker identififer for miners using multiple rigs + /// + public override string Worker { get; set; } + + /// + /// Unique value assigned per worker + /// + public string ExtraNonce1 { get; set; } + + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); + + public virtual void AddJob(NexaJob job, int maxActiveJobs) + { + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); + + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); + } + + public NexaJob GetJob(string jobId) + { + return validJobs.ToArray().FirstOrDefault(x => x.JobId == jobId); + } +} diff --git a/src/Miningcore/Blockchain/Progpow/Custom/Kiiro/KiiroJob.cs b/src/Miningcore/Blockchain/Progpow/Custom/Kiiro/KiiroJob.cs deleted file mode 100644 index 0d2be4bd1d..0000000000 --- a/src/Miningcore/Blockchain/Progpow/Custom/Kiiro/KiiroJob.cs +++ /dev/null @@ -1,242 +0,0 @@ -using System.Globalization; -using System.Text; -using Miningcore.Blockchain.Bitcoin; -using Miningcore.Blockchain.Bitcoin.DaemonResponses; -using Miningcore.Crypto; -using Miningcore.Crypto.Hashing.Progpow; -using Miningcore.Extensions; -using Miningcore.Stratum; -using Miningcore.Time; -using Miningcore.Util; -using NBitcoin; -using NBitcoin.DataEncoders; -using Newtonsoft.Json.Linq; -using NLog; -using Transaction = NBitcoin.Transaction; - -namespace Miningcore.Blockchain.Progpow.Custom.Kiiro; - -public class KiiroJob : ProgpowJob -{ - public override (Share Share, string BlockHex) ProcessShareInternal(ILogger logger, - StratumConnection worker, ulong nonce, string inputHeaderHash, string mixHash) - { - var context = worker.ContextAs(); - var extraNonce1 = context.ExtraNonce1; - - // build coinbase - var coinbase = SerializeCoinbase(extraNonce1); - Span coinbaseHash = stackalloc byte[32]; - coinbaseHasher.Digest(coinbase, coinbaseHash); - - // hash block-header - var headerBytes = SerializeHeader(coinbaseHash); - Span headerHash = stackalloc byte[32]; - headerHasher.Digest(headerBytes, headerHash); - headerHash.Reverse(); - - var headerHashHex = headerHash.ToHexString(); - - if(headerHashHex != inputHeaderHash) - throw new StratumException(StratumError.MinusOne, $"bad header-hash"); - - if(!progpowHasher.Compute(logger, (int) BlockTemplate.Height, headerHash.ToArray(), nonce, out var mixHashOut, out var resultBytes)) - throw new StratumException(StratumError.MinusOne, "bad hash"); - - if(mixHash != mixHashOut.ToHexString()) - throw new StratumException(StratumError.MinusOne, $"bad mix-hash"); - - resultBytes.ReverseInPlace(); - mixHashOut.ReverseInPlace(); - - var resultValue = new uint256(resultBytes); - var resultValueBig = resultBytes.AsSpan().ToBigInteger(); - // calc share-diff - var shareDiff = (double) new BigRational(FiroConstants.Diff1, resultValueBig) * shareMultiplier; - var stratumDifficulty = context.Difficulty; - var ratio = shareDiff / stratumDifficulty; - - // check if the share meets the much harder block difficulty (block candidate) - var isBlockCandidate = resultValue <= blockTargetValue; - - // test if share meets at least workers current difficulty - 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) - { - ratio = shareDiff / context.PreviousDifficulty.Value; - - if(ratio < 0.99) - throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); - - // use previous difficulty - stratumDifficulty = context.PreviousDifficulty.Value; - } - - else - throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); - } - - var result = new Share - { - BlockHeight = BlockTemplate.Height, - NetworkDifficulty = Difficulty, - Difficulty = stratumDifficulty / shareMultiplier, - }; - - if(!isBlockCandidate) - { - return (result, null); - } - - result.IsBlockCandidate = true; - - var nonceBytes = (Span) nonce.ToString("X").HexToReverseByteArray(); - var mixHashBytes = (Span) mixHash.HexToReverseByteArray(); - // concat headerBytes, nonceBytes and mixHashBytes - Span headerBytesNonceMixHasBytes = stackalloc byte[headerBytes.Length + nonceBytes.Length + mixHashBytes.Length]; - headerBytes.CopyTo(headerBytesNonceMixHasBytes); - var offset = headerBytes.Length; - nonceBytes.CopyTo(headerBytesNonceMixHasBytes[offset..]); - offset += nonceBytes.Length; - mixHashBytes.CopyTo(headerBytesNonceMixHasBytes[offset..]); - - Span blockHash = stackalloc byte[32]; - blockHasher.Digest(headerBytesNonceMixHasBytes, blockHash); - result.BlockHash = blockHash.ToHexString(); - - var blockBytes = SerializeBlock(headerBytes, coinbase, nonce, mixHashOut); - var blockHex = blockBytes.ToHexString(); - - return (result, blockHex); - } - - #region Masternodes - - protected override Money CreateMasternodeOutputs(Transaction tx, Money reward) - { - if(masterNodeParameters.Masternode != null) - { - Masternode[] masternodes; - - // Dash v13 Multi-Master-Nodes - if(masterNodeParameters.Masternode.Type == JTokenType.Array) - masternodes = masterNodeParameters.Masternode.ToObject(); - else - masternodes = new[] { masterNodeParameters.Masternode.ToObject() }; - - if(masternodes != null) - { - foreach(var masterNode in masternodes) - { - if(!string.IsNullOrEmpty(masterNode.Script)) - { - Script payeeAddress = new (masterNode.Script.HexToByteArray()); - var payeeReward = masterNode.Amount; - - tx.Outputs.Add(payeeReward, payeeAddress); - /* A block reward of 30 KIIRO/block is divided as follows: - - Miners (20%, 6 KIIRO) - Masternodes (61%, 18.3 KIIRO) - DataMining Fund (1%, 0.3 KIIRO) - Developer Fund (9%, 2.7 KIIRO) - Community Fund (9%, 2.7 KIIRO) - */ - //reward -= payeeReward; // KIIRO does not deduct payeeReward from coinbasevalue (reward) since it's the amount which goes to miners - } - } - } - } - - return reward; - } - - #endregion // Masternodes - - #region Community - - protected override Money CreateCommunityOutputs(Transaction tx, Money reward) - { - if (communityParameters.Community != null) - { - Community[] communitys; - if (communityParameters.Community.Type == JTokenType.Array) - communitys = communityParameters.Community.ToObject(); - else - communitys = new[] { communityParameters.Community.ToObject() }; - - if(communitys != null) - { - foreach(var Community in communitys) - { - if(!string.IsNullOrEmpty(Community.Script)) - { - Script payeeAddress = new (Community.Script.HexToByteArray()); - var payeeReward = Community.Amount; - - tx.Outputs.Add(payeeReward, payeeAddress); - /* A block reward of 30 KIIRO/block is divided as follows: - - Miners (20%, 6 KIIRO) - Masternodes (61%, 18.3 KIIRO) - DataMining Fund (1%, 0.3 KIIRO) - Developer Fund (9%, 2.7 KIIRO) - Community Fund (9%, 2.7 KIIRO) - */ - //reward -= payeeReward; // KIIRO does not deduct payeeReward from coinbasevalue (reward) since it's the amount which goes to miners - - } - } - } - } - - return reward; - } - - #endregion //Community - - #region Developer - - protected override Money CreateDeveloperOutputs(Transaction tx, Money reward) - { - if (developerParameters.Developer != null) - { - Developer[] developers; - if (developerParameters.Developer.Type == JTokenType.Array) - developers = developerParameters.Developer.ToObject(); - else - developers = new[] { developerParameters.Developer.ToObject() }; - - if(developers != null) - { - foreach(var Developer in developers) - { - if(!string.IsNullOrEmpty(Developer.Script)) - { - Script payeeAddress = new (Developer.Script.HexToByteArray()); - var payeeReward = Developer.Amount; - - tx.Outputs.Add(payeeReward, payeeAddress); - /* A block reward of 30 KIIRO/block is divided as follows: - - Miners (20%, 6 KIIRO) - Masternodes (61%, 18.3 KIIRO) - DataMining Fund (1%, 0.3 KIIRO) - Developer Fund (9%, 2.7 KIIRO) - Community Fund (9%, 2.7 KIIRO) - */ - //reward -= payeeReward; // KIIRO does not deduct payeeReward from coinbasevalue (reward) since it's the amount which goes to miners - - } - } - } - } - - return reward; - } - - #endregion //Developer - - } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Progpow/Custom/Privora/PrivoraJob.cs b/src/Miningcore/Blockchain/Progpow/Custom/Privora/PrivoraJob.cs deleted file mode 100644 index ad9ddc730b..0000000000 --- a/src/Miningcore/Blockchain/Progpow/Custom/Privora/PrivoraJob.cs +++ /dev/null @@ -1,172 +0,0 @@ -using System.Globalization; -using System.Text; -using Miningcore.Blockchain.Bitcoin; -using Miningcore.Blockchain.Bitcoin.DaemonResponses; -using Miningcore.Crypto; -using Miningcore.Crypto.Hashing.Progpow; -using Miningcore.Extensions; -using Miningcore.Stratum; -using Miningcore.Time; -using Miningcore.Util; -using NBitcoin; -using NBitcoin.DataEncoders; -using Newtonsoft.Json.Linq; -using NLog; -using Transaction = NBitcoin.Transaction; - -namespace Miningcore.Blockchain.Progpow.Custom.Privora; - -public class PrivoraJob : ProgpowJob -{ - public override (Share Share, string BlockHex) ProcessShareInternal(ILogger logger, StratumConnection worker, ulong nonce, string inputHeaderHash, string mixHash) - { - var context = worker.ContextAs(); - var extraNonce1 = context.ExtraNonce1; - - // build coinbase - var coinbase = SerializeCoinbase(extraNonce1); - Span coinbaseHash = stackalloc byte[32]; - coinbaseHasher.Digest(coinbase, coinbaseHash); - - // hash block-header - var headerBytes = SerializeHeader(coinbaseHash); - Span headerHash = stackalloc byte[32]; - headerHasher.Digest(headerBytes, headerHash); - headerHash.Reverse(); - - var headerHashHex = headerHash.ToHexString(); - - if(headerHashHex != inputHeaderHash) - throw new StratumException(StratumError.MinusOne, $"bad header-hash"); - - if(!progpowHasher.Compute(logger, (int) BlockTemplate.Height, headerHash.ToArray(), nonce, out var mixHashOut, out var resultBytes)) - throw new StratumException(StratumError.MinusOne, "bad hash"); - - if(mixHash != mixHashOut.ToHexString()) - throw new StratumException(StratumError.MinusOne, $"bad mix-hash"); - - resultBytes.ReverseInPlace(); - mixHashOut.ReverseInPlace(); - - var resultValue = new uint256(resultBytes); - var resultValueBig = resultBytes.AsSpan().ToBigInteger(); - - // calc share-diff - var shareDiff = (double) new BigRational(FiroConstants.Diff1, resultValueBig) * shareMultiplier; - var stratumDifficulty = context.Difficulty; - var ratio = shareDiff / stratumDifficulty; - - // check if the share meets the much harder block difficulty (block candidate) - var isBlockCandidate = resultValue <= blockTargetValue; - - // test if share meets at least workers current difficulty - 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) - { - ratio = shareDiff / context.PreviousDifficulty.Value; - - if(ratio < 0.99) - throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); - - // use previous difficulty - stratumDifficulty = context.PreviousDifficulty.Value; - } - else - { - throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); - } - } - - var result = new Share - { - BlockHeight = BlockTemplate.Height, - NetworkDifficulty = Difficulty, - Difficulty = stratumDifficulty / shareMultiplier, - }; - - if(!isBlockCandidate) - { - return (result, null); - } - - result.IsBlockCandidate = true; - result.BlockHash = resultBytes.ReverseInPlace().ToHexString(); - - var blockBytes = SerializeBlock(headerBytes, coinbase, nonce, mixHashOut); - var blockHex = blockBytes.ToHexString(); - - return (result, blockHex); - } - - #region Masternodes - - protected override Money CreateMasternodeOutputs(Transaction tx, Money reward) - { - if(masterNodeParameters.Masternode != null) - { - Masternode[] masternodes; - - // Dash v13 Multi-Master-Nodes - if(masterNodeParameters.Masternode.Type == JTokenType.Array) - masternodes = masterNodeParameters.Masternode.ToObject(); - else - masternodes = new[] { masterNodeParameters.Masternode.ToObject() }; - - if(masternodes != null) - { - foreach(var masterNode in masternodes) - { - if(!string.IsNullOrEmpty(masterNode.Payee)) - { - var payeeDestination = BitcoinUtils.AddressToDestination(masterNode.Payee, network); - var payeeReward = masterNode.Amount; - - tx.Outputs.Add(payeeReward, payeeDestination); - //reward -= payeeReward; // VORA does not deduct payeeReward from coinbasevalue (reward) since it's the amount which goes to miners - } - } - } - } - - return reward; - } - - #endregion // Masternodes - - #region Founder - - protected override Money CreateFounderOutputs(Transaction tx, Money reward) - { - if (coin.HasFounderFee) - { - Founder[] founders; - - if(network.Name.ToLower() == "testnet") - { - founders = new[] { new Founder{ Payee = "TwnodAoZDovgCPq14Qif3EzeYj7FEF4vqf", Amount = 1000000000 } }; - } - else - { - founders = new[] { new Founder{ Payee = "PfadcTvPhr8L9k6jaRbXT1mwgp8U8jXcp1", Amount = 1000000000 } }; - } - - - foreach(var Founder in founders) - { - if(!string.IsNullOrEmpty(Founder.Payee)) - { - var payeeAddress = BitcoinUtils.AddressToDestination(Founder.Payee, network); - var payeeReward = Founder.Amount; - tx.Outputs.Add(payeeReward, payeeAddress); - //reward -= payeeReward; // VORA does not deduct payeeReward from coinbasevalue (reward) since it's the amount which goes to miners - } - } - } - - return reward; - } - - #endregion // Founder -} diff --git a/src/Miningcore/Blockchain/Progpow/Custom/Realichain/RealichainJob.cs b/src/Miningcore/Blockchain/Progpow/Custom/Realichain/RealichainJob.cs deleted file mode 100644 index c80a36a440..0000000000 --- a/src/Miningcore/Blockchain/Progpow/Custom/Realichain/RealichainJob.cs +++ /dev/null @@ -1,241 +0,0 @@ -using System.Globalization; -using System.Text; -using Miningcore.Blockchain.Bitcoin; -using Miningcore.Blockchain.Bitcoin.DaemonResponses; -using Miningcore.Crypto; -using Miningcore.Crypto.Hashing.Progpow; -using Miningcore.Extensions; -using Miningcore.Stratum; -using Miningcore.Time; -using Miningcore.Util; -using NBitcoin; -using NBitcoin.DataEncoders; -using Newtonsoft.Json.Linq; -using NLog; -using Transaction = NBitcoin.Transaction; - -namespace Miningcore.Blockchain.Progpow.Custom.Realichain; - -public class RealichainJob : ProgpowJob -{ - public override (Share Share, string BlockHex) ProcessShareInternal(ILogger logger, - StratumConnection worker, ulong nonce, string inputHeaderHash, string mixHash) - { - var context = worker.ContextAs(); - var extraNonce1 = context.ExtraNonce1; - - // build coinbase - var coinbase = SerializeCoinbase(extraNonce1); - Span coinbaseHash = stackalloc byte[32]; - coinbaseHasher.Digest(coinbase, coinbaseHash); - - // hash block-header - var headerBytes = SerializeHeader(coinbaseHash); - Span headerHash = stackalloc byte[32]; - headerHasher.Digest(headerBytes, headerHash); - headerHash.Reverse(); - - var headerHashHex = headerHash.ToHexString(); - - if(headerHashHex != inputHeaderHash) - throw new StratumException(StratumError.MinusOne, $"bad header-hash"); - - if(!progpowHasher.Compute(logger, (int) BlockTemplate.Height, headerHash.ToArray(), nonce, out var mixHashOut, out var resultBytes)) - throw new StratumException(StratumError.MinusOne, "bad hash"); - - if(mixHash != mixHashOut.ToHexString()) - throw new StratumException(StratumError.MinusOne, $"bad mix-hash"); - - resultBytes.ReverseInPlace(); - mixHashOut.ReverseInPlace(); - - var resultValue = new uint256(resultBytes); - var resultValueBig = resultBytes.AsSpan().ToBigInteger(); - // calc share-diff - var shareDiff = (double) new BigRational(FiroConstants.Diff1, resultValueBig) * shareMultiplier; - var stratumDifficulty = context.Difficulty; - var ratio = shareDiff / stratumDifficulty; - - // check if the share meets the much harder block difficulty (block candidate) - var isBlockCandidate = resultValue <= blockTargetValue; - - // test if share meets at least workers current difficulty - 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) - { - ratio = shareDiff / context.PreviousDifficulty.Value; - - if(ratio < 0.99) - throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); - - // use previous difficulty - stratumDifficulty = context.PreviousDifficulty.Value; - } - - else - throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); - } - - var result = new Share - { - BlockHeight = BlockTemplate.Height, - NetworkDifficulty = Difficulty, - Difficulty = stratumDifficulty / shareMultiplier, - }; - - if(!isBlockCandidate) - { - return (result, null); - } - - result.IsBlockCandidate = true; - - var nonceBytes = (Span) nonce.ToString("X").HexToReverseByteArray(); - var mixHashBytes = (Span) mixHash.HexToReverseByteArray(); - // concat headerBytes, nonceBytes and mixHashBytes - Span headerBytesNonceMixHasBytes = stackalloc byte[headerBytes.Length + nonceBytes.Length + mixHashBytes.Length]; - headerBytes.CopyTo(headerBytesNonceMixHasBytes); - var offset = headerBytes.Length; - nonceBytes.CopyTo(headerBytesNonceMixHasBytes[offset..]); - offset += nonceBytes.Length; - mixHashBytes.CopyTo(headerBytesNonceMixHasBytes[offset..]); - - Span blockHash = stackalloc byte[32]; - blockHasher.Digest(headerBytesNonceMixHasBytes, blockHash); - result.BlockHash = blockHash.ToHexString(); - - var blockBytes = SerializeBlock(headerBytes, coinbase, nonce, mixHashOut); - var blockHex = blockBytes.ToHexString(); - - return (result, blockHex); - } - - #region Masternodes - - protected override Money CreateMasternodeOutputs(Transaction tx, Money reward) - { - if(masterNodeParameters.Masternode != null) - { - Masternode[] masternodes; - - // Dash v13 Multi-Master-Nodes - if(masterNodeParameters.Masternode.Type == JTokenType.Array) - masternodes = masterNodeParameters.Masternode.ToObject(); - else - masternodes = new[] { masterNodeParameters.Masternode.ToObject() }; - - if(masternodes != null) - { - foreach(var masterNode in masternodes) - { - if(!string.IsNullOrEmpty(masterNode.Script)) - { - Script payeeAddress = new (masterNode.Script.HexToByteArray()); - var payeeReward = masterNode.Amount; - - tx.Outputs.Add(payeeReward, payeeAddress); - /* A block reward of 4 REALI/block is divided as follows: - - Miners (20%, 0.8 REALI) - Masternodes (37%, 1.48 REALI) - DataMining Fund (2%, 0.08 REALI) - Developer Fund (8%, 0.32 REALI) - Community Fund (33%, 1.32 REALI) - */ - //reward -= payeeReward; // REALI does not deduct payeeReward from coinbasevalue (reward) since it's the amount which goes to miners - } - } - } - } - - return reward; - } - - #endregion // Masternodes - - #region Community - - protected override Money CreateCommunityOutputs(Transaction tx, Money reward) - { - if (communityParameters.Community != null) - { - Community[] communitys; - if (communityParameters.Community.Type == JTokenType.Array) - communitys = communityParameters.Community.ToObject(); - else - communitys = new[] { communityParameters.Community.ToObject() }; - - if(communitys != null) - { - foreach(var Community in communitys) - { - if(!string.IsNullOrEmpty(Community.Script)) - { - Script payeeAddress = new (Community.Script.HexToByteArray()); - var payeeReward = Community.Amount; - - tx.Outputs.Add(payeeReward, payeeAddress); - /* A block reward of 4 REALI/block is divided as follows: - - Miners (20%, 0.8 REALI) - Masternodes (37%, 1.48 REALI) - DataMining Fund (2%, 0.08 REALI) - Developer Fund (8%, 0.32 REALI) - Community Fund (33%, 1.32 REALI) - */ - //reward -= payeeReward; // REALI does not deduct payeeReward from coinbasevalue (reward) since it's the amount which goes to miners - - } - } - } - } - - return reward; - } - - #endregion //Community - - #region Developer - - protected override Money CreateDeveloperOutputs(Transaction tx, Money reward) - { - if (developerParameters.Developer != null) - { - Developer[] developers; - if (developerParameters.Developer.Type == JTokenType.Array) - developers = developerParameters.Developer.ToObject(); - else - developers = new[] { developerParameters.Developer.ToObject() }; - - if(developers != null) - { - foreach(var Developer in developers) - { - if(!string.IsNullOrEmpty(Developer.Script)) - { - Script payeeAddress = new (Developer.Script.HexToByteArray()); - var payeeReward = Developer.Amount; - - tx.Outputs.Add(payeeReward, payeeAddress); - /* A block reward of 4 REALI/block is divided as follows: - - Miners (20%, 0.8 REALI) - Masternodes (37%, 1.48 REALI) - DataMining Fund (2%, 0.08 REALI) - Developer Fund (8%, 0.32 REALI) - Community Fund (33%, 1.32 REALI) - */ - //reward -= payeeReward; // REALI does not deduct payeeReward from coinbasevalue (reward) since it's the amount which goes to miners - - } - } - } - } - - return reward; - } - - #endregion //Developer - } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Progpow/Custom/Telestai/TelestaiJob.cs b/src/Miningcore/Blockchain/Progpow/Custom/Telestai/TelestaiJob.cs deleted file mode 100644 index 11750b6823..0000000000 --- a/src/Miningcore/Blockchain/Progpow/Custom/Telestai/TelestaiJob.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System.Globalization; -using System.Text; -using Miningcore.Blockchain.Bitcoin; -using Miningcore.Blockchain.Bitcoin.DaemonResponses; -using Miningcore.Crypto; -using Miningcore.Crypto.Hashing.Progpow; -using Miningcore.Extensions; -using Miningcore.Stratum; -using Miningcore.Time; -using Miningcore.Util; -using NBitcoin; -using NBitcoin.DataEncoders; -using Newtonsoft.Json.Linq; -using NLog; -using Transaction = NBitcoin.Transaction; - -namespace Miningcore.Blockchain.Progpow.Custom.Telestai; - -public class TelestaiJob : ProgpowJob -{ - public override (Share Share, string BlockHex) ProcessShareInternal(ILogger logger, - StratumConnection worker, ulong nonce, string inputHeaderHash, string mixHash) - { - var context = worker.ContextAs(); - var extraNonce1 = context.ExtraNonce1; - - // build coinbase - var coinbase = SerializeCoinbase(extraNonce1); - Span coinbaseHash = stackalloc byte[32]; - coinbaseHasher.Digest(coinbase, coinbaseHash); - - // hash block-header - var headerBytes = SerializeHeader(coinbaseHash); - Span headerHash = stackalloc byte[32]; - headerHasher.Digest(headerBytes, headerHash); - headerHash.Reverse(); - - var headerHashHex = headerHash.ToHexString(); - - if(headerHashHex != inputHeaderHash) - throw new StratumException(StratumError.MinusOne, $"bad header-hash"); - - if(!progpowHasher.Compute(logger, (int) BlockTemplate.Height, headerHash.ToArray(), nonce, out var mixHashOut, out var resultBytes)) - throw new StratumException(StratumError.MinusOne, "bad hash"); - - if(mixHash != mixHashOut.ToHexString()) - throw new StratumException(StratumError.MinusOne, $"bad mix-hash"); - - resultBytes.ReverseInPlace(); - mixHashOut.ReverseInPlace(); - - var resultValue = new uint256(resultBytes); - var resultValueBig = resultBytes.AsSpan().ToBigInteger(); - // calc share-diff - var shareDiff = (double) new BigRational(TelestaiConstants.Diff1, resultValueBig) * shareMultiplier; - var stratumDifficulty = context.Difficulty; - var ratio = shareDiff / stratumDifficulty; - - // check if the share meets the much harder block difficulty (block candidate) - var isBlockCandidate = resultValue <= blockTargetValue; - - // test if share meets at least workers current difficulty - 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) - { - ratio = shareDiff / context.PreviousDifficulty.Value; - - if(ratio < 0.99) - throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); - - // use previous difficulty - stratumDifficulty = context.PreviousDifficulty.Value; - } - - else - throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); - } - - var result = new Share - { - BlockHeight = BlockTemplate.Height, - NetworkDifficulty = Difficulty, - Difficulty = stratumDifficulty / shareMultiplier, - }; - - if(!isBlockCandidate) - { - return (result, null); - } - - result.IsBlockCandidate = true; - result.BlockHash = resultBytes.ReverseInPlace().ToHexString(); - - var blockBytes = SerializeBlock(headerBytes, coinbase, nonce, mixHashOut); - var blockHex = blockBytes.ToHexString(); - - return (result, blockHex); - } - - #region Founder - - protected override Money CreateFounderOutputs(Transaction tx, Money reward) - { - if (coin.HasFounderFee) - { - Founder[] founders; - - if(network.Name.ToLower() == "testnet") - { - founders = new[] { new Founder{ Payee = "nVG96MbaKEDFzzj9NzbAuxkDt86KAm2Qj5", Amount = 11700000000 } }; - } - else - { - founders = new[] { new Founder{ Payee = "TesBmcgLQsowvYEYPXpSHkkapoTbVV7Xfe", Amount = 11700000000 } }; - } - - foreach(var Founder in founders) - { - if(!string.IsNullOrEmpty(Founder.Payee)) - { - var payeeAddress = BitcoinUtils.AddressToDestination(Founder.Payee, network); - var payeeReward = Founder.Amount; - - tx.Outputs.Add(payeeReward, payeeAddress); - reward -= payeeReward; - } - } - } - - return reward; - } - - #endregion // Founder -} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowConstants.cs b/src/Miningcore/Blockchain/Progpow/ProgpowConstants.cs index 5d6b6d000d..8d8efb811e 100644 --- a/src/Miningcore/Blockchain/Progpow/ProgpowConstants.cs +++ b/src/Miningcore/Blockchain/Progpow/ProgpowConstants.cs @@ -4,16 +4,6 @@ namespace Miningcore.Blockchain.Progpow; -public class EvrmoreConstants -{ - public const int EpochLength = 12000; - public static BigInteger BigMaxValue = BigInteger.Pow(2, 256); - public static readonly BigInteger Diff1B = BigInteger.Parse("00000000ff000000000000000000000000000000000000000000000000000000", NumberStyles.AllowHexSpecifier, null); - public static readonly BigInteger Diff1 = BigInteger.Parse("00000000ff000000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); - public const int ExtranoncePlaceHolderLength = 2; - public static double Multiplier = (double) new BigRational(BigMaxValue, Diff1); -} - public class FiroConstants { public const int EpochLength = 1300; @@ -32,35 +22,4 @@ public class RavencoinConstants public static readonly BigInteger Diff1 = BigInteger.Parse("00000000ff000000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); public const int ExtranoncePlaceHolderLength = 2; public static double Multiplier = (double) new BigRational(BigMaxValue, Diff1); -} - -public class SccConstants -{ - public const int EpochLength = 3240; - public static BigInteger BigMaxValue = BigInteger.Pow(2, 256); - public static readonly BigInteger Diff1B = BigInteger.Parse("00000000ffff0000000000000000000000000000000000000000000000000000", NumberStyles.AllowHexSpecifier, null); - public static readonly BigInteger Diff1 = BigInteger.Parse("00000000ffff0000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); - public const int ExtranoncePlaceHolderLength = 2; - public static double Multiplier = (double) new BigRational(BigMaxValue, Diff1); -} - -public class TelestaiConstants -{ - public const int EpochLength = 27500; - public static BigInteger BigMaxValue = BigInteger.Pow(2, 256); - public static readonly BigInteger Diff1B = BigInteger.Parse("00000000ff000000000000000000000000000000000000000000000000000000", NumberStyles.AllowHexSpecifier, null); - public static readonly BigInteger Diff1 = BigInteger.Parse("00000000ff000000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); - public const int ExtranoncePlaceHolderLength = 2; - public static double Multiplier = (double) new BigRational(BigMaxValue, Diff1); -} - -public class PhicoinConstants -{ - public const int EpochLength = 30000; - public static BigInteger BigMaxValue = BigInteger.Pow(2, 256); - public static readonly BigInteger Diff1B = BigInteger.Parse("00000000ff000000000000000000000000000000000000000000000000000000", NumberStyles.AllowHexSpecifier, null); - public static readonly BigInteger Diff1 = BigInteger.Parse("00000000ff000000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); - public const int ExtranoncePlaceHolderLength = 2; - public static double Multiplier = (double) new BigRational(BigMaxValue, Diff1); -} - +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowJob.cs b/src/Miningcore/Blockchain/Progpow/ProgpowJob.cs index dc01072950..23798edabe 100644 --- a/src/Miningcore/Blockchain/Progpow/ProgpowJob.cs +++ b/src/Miningcore/Blockchain/Progpow/ProgpowJob.cs @@ -206,12 +206,12 @@ public virtual void Init(BlockTemplate blockTemplate, string jobId, this.extraNoncePlaceHolderLength = RavencoinConstants.ExtranoncePlaceHolderLength; this.shareMultiplier = shareMultiplier; - + if(coin.HasMasterNodes) { masterNodeParameters = BlockTemplate.Extra.SafeExtensionDataAs(); - if(coin.Symbol == "FIRO" || coin.Symbol == "KIIRO" || coin.Symbol == "REALI" || coin.Symbol == "VORA") + if(coin.Symbol == "FIRO") { if(masterNodeParameters.Extra?.ContainsKey("znode") == true) { @@ -219,14 +219,6 @@ public virtual void Init(BlockTemplate blockTemplate, string jobId, } } - if(coin.HasSmartNodes) - { - if(masterNodeParameters.Extra?.ContainsKey("smartnode") == true) - { - masterNodeParameters.Masternode = JToken.FromObject(masterNodeParameters.Extra["smartnode"]); - } - } - if(!string.IsNullOrEmpty(masterNodeParameters.CoinbasePayload)) { txVersion = 3; @@ -234,35 +226,13 @@ public virtual void Init(BlockTemplate blockTemplate, string jobId, txVersion += txType << 16; } } - + if(coin.HasPayee) payeeParameters = BlockTemplate.Extra.SafeExtensionDataAs(); - if(coin.HasCommunity) - communityParameters = BlockTemplate.Extra.SafeExtensionDataAs(); - - if(coin.HasDataMining) - dataminingParameters = BlockTemplate.Extra.SafeExtensionDataAs(); - - if(coin.HasDeveloper) - developerParameters = BlockTemplate.Extra.SafeExtensionDataAs(); - if (coin.HasFounderFee) - { founderParameters = BlockTemplate.Extra.SafeExtensionDataAs(); - if(coin.HasDevFee) - { - if(founderParameters.Extra?.ContainsKey("devfee") == true) - { - founderParameters.Founder = JToken.FromObject(founderParameters.Extra["devfee"]); - } - } - } - - if (coin.HasMinerDevFund) - minerDevFundParameters = BlockTemplate.Extra.SafeExtensionDataAs("coinbasetxn", "minerdevfund"); - if (coin.HasMinerFund) minerFundParameters = BlockTemplate.Extra.SafeExtensionDataAs("coinbasetxn", "minerfund"); @@ -270,7 +240,7 @@ public virtual void Init(BlockTemplate blockTemplate, string jobId, this.headerHasher = headerHasher; this.blockHasher = blockHasher; this.progpowHasher = progpowHasher; - + if(!string.IsNullOrEmpty(BlockTemplate.Target)) this.blockTargetValue = new uint256(BlockTemplate.Target); else @@ -324,4 +294,4 @@ private string CreateHeaderHash(ProgpowWorkerJob workerJob) #endregion // API-Surface -} +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowJobManager.cs b/src/Miningcore/Blockchain/Progpow/ProgpowJobManager.cs index 202cbb6923..5f5ca7a640 100644 --- a/src/Miningcore/Blockchain/Progpow/ProgpowJobManager.cs +++ b/src/Miningcore/Blockchain/Progpow/ProgpowJobManager.cs @@ -3,10 +3,6 @@ using Miningcore.Blockchain.Bitcoin.Configuration; using Miningcore.Blockchain.Bitcoin.DaemonResponses; using Miningcore.Blockchain.Progpow.Custom.Firo; -using Miningcore.Blockchain.Progpow.Custom.Kiiro; -using Miningcore.Blockchain.Progpow.Custom.Privora; -using Miningcore.Blockchain.Progpow.Custom.Realichain; -using Miningcore.Blockchain.Progpow.Custom.Telestai; using Miningcore.Configuration; using Miningcore.Contracts; using Miningcore.Crypto; @@ -55,21 +51,8 @@ private ProgpowJob CreateJob() { case "FIRO": return new FiroJob(); - - case "KIIRO": - return new KiiroJob(); - - case "REALI": - return new RealichainJob(); - - case "TLS": - return new TelestaiJob(); - - case "VORA": - return new PrivoraJob(); - } - + return new ProgpowJob(); } @@ -203,6 +186,12 @@ protected override object GetJobParamsForStratum(bool isNew) return job?.GetJobParams(isNew); } + public override ProgpowJob GetJobForStratum() + { + var job = currentJob; + return job; + } + #region API-Surface public override void Configure(PoolConfig pc, ClusterConfig cc) @@ -282,7 +271,7 @@ public async ValueTask SubmitShareAsync(StratumConnection worker, object lock(context) { - if((job = context.FindJob(jobId)) == null) + if((job = context.GetJob(jobId)) == null) throw new StratumException(StratumError.MinusOne, "invalid jobid"); } @@ -334,4 +323,4 @@ public async ValueTask SubmitShareAsync(StratumConnection worker, object } #endregion // API-Surface -} +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowPool.cs b/src/Miningcore/Blockchain/Progpow/ProgpowPool.cs index 98d5e03a18..6e2a4bfdf1 100644 --- a/src/Miningcore/Blockchain/Progpow/ProgpowPool.cs +++ b/src/Miningcore/Blockchain/Progpow/ProgpowPool.cs @@ -47,8 +47,6 @@ private string createEncodeTarget(double difficulty) switch(coin.Symbol) { case "FIRO": - case "KIIRO": - case "REALI": return ProgpowUtils.FiroEncodeTarget(difficulty); default: @@ -77,7 +75,18 @@ protected virtual async Task OnSubscribeAsync(StratumConnection connection, Time .Concat(manager.GetSubscriberData(connection)) .ToArray(); - await connection.RespondAsync(data, request.Id); + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(data, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // setup worker context context.IsSubscribed = true; @@ -125,48 +134,38 @@ protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Time if(context.IsAuthorized) { + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(context.IsAuthorized, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + // respond - await connection.RespondAsync(context.IsAuthorized, request.Id); + await connection.RespondAsync(response); // log association logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); // extract control vars from password var staticDiff = GetStaticDiffFromPassparts(passParts); - var startDiff = GetStartDiffFromPassparts(passParts); - - // Start diff - if(startDiff.HasValue) - { - if(context.VarDiff != null && startDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && startDiff.Value > context.Difficulty) - { - context.SetDifficulty(startDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {startDiff.Value}"); - } - else - { - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Start difficulty set to {context.VarDiff.Config.MinDiff}"); - } - } - - // Static diff - if(staticDiff.HasValue && !startDiff.HasValue) - { - if(context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty) - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(staticDiff.Value); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); - } - else - { - context.VarDiff = null; // disable vardiff - context.SetDifficulty(context.VarDiff.Config.MinDiff); - logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {context.VarDiff.Config.MinDiff}"); - } - } - await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + + // Static diff + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) + { + context.VarDiff = null; // disable vardiff + context.SetDifficulty(staticDiff.Value); + + logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); + + await connection.NotifyAsync(ProgpowStratumMethods.SetDifficulty, new object[] { createEncodeTarget(context.Difficulty) }); + } } else @@ -206,7 +205,7 @@ private object CreateWorkerJob(StratumConnection connection, bool update) // update context lock(context) { - context.AddJob(job); + context.AddJob(job, manager.maxActiveJobs); } return result; @@ -249,7 +248,19 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta // submit var share = await manager.SubmitShareAsync(connection, requestParams, ct); - await connection.RespondAsync(true, request.Id); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // publish messageBus.SendMessage(share); @@ -257,7 +268,7 @@ protected virtual async Task OnSubmitAsync(StratumConnection connection, Timesta // telemetry PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, true); - logger.Info(() => $"[{connection.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty * coin.ShareMultiplier, 9)}"); + logger.Info(() => $"[{connection.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty * coin.ShareMultiplier, 3)}"); // update pool stats if(share.IsBlockCandidate) @@ -323,8 +334,6 @@ private ProgpowJobManager createProgpowExtraNonceProvider() switch(coin.Symbol) { case "FIRO": - case "KIIRO": - case "REALI": return ctx.Resolve(new TypedParameter(typeof(IExtraNonceProvider), new FiroExtraNonceProvider(poolConfig.Id, clusterConfig.InstanceId))); default: diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowWorkerContext.cs b/src/Miningcore/Blockchain/Progpow/ProgpowWorkerContext.cs index fbf439aee3..0f35e0a2c2 100644 --- a/src/Miningcore/Blockchain/Progpow/ProgpowWorkerContext.cs +++ b/src/Miningcore/Blockchain/Progpow/ProgpowWorkerContext.cs @@ -1,3 +1,6 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; using Miningcore.Mining; namespace Miningcore.Blockchain.Progpow; @@ -7,30 +10,34 @@ public class ProgpowWorkerContext : WorkerContextBase /// /// Usually a wallet address /// - public string Miner { get; set; } + public override string Miner { get; set; } /// /// Arbitrary worker identififer for miners using multiple rigs /// - public string Worker { get; set; } + public override string Worker { get; set; } /// /// Unique value assigned per worker /// public string ExtraNonce1 { get; set; } - private List ValidJobs { get; } = new(); + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); - public void AddJob(ProgpowWorkerJob job) + public virtual void AddJob(ProgpowWorkerJob job, int maxActiveJobs) { - ValidJobs.Insert(0, job); + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); - while(ValidJobs.Count > 4) - ValidJobs.RemoveAt(ValidJobs.Count - 1); + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); } - public ProgpowWorkerJob FindJob(string jobId) + public ProgpowWorkerJob GetJob(string jobId) { - return ValidJobs.FirstOrDefault(x => x.Id == jobId); + return validJobs.ToArray().FirstOrDefault(x => x.Id == jobId); } } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Warthog/Configuration/WarthogDaemonEndpointConfigExtra.cs b/src/Miningcore/Blockchain/Warthog/Configuration/WarthogDaemonEndpointConfigExtra.cs new file mode 100644 index 0000000000..5dca5a3be1 --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/Configuration/WarthogDaemonEndpointConfigExtra.cs @@ -0,0 +1,19 @@ +namespace Miningcore.Blockchain.Warthog.Configuration; + +public class WarthogDaemonEndpointConfigExtra +{ + /// + /// Optional port for streaming WebSocket data + /// + public int? PortWs { get; set; } + + /// + /// Optional http-path for streaming WebSocket data + /// + public string HttpPathWs { get; set; } + + /// + /// Optional: Use SSL to for daemon websocket streaming + /// + public bool SslWs { get; set; } +} diff --git a/src/Miningcore/Blockchain/Warthog/Configuration/WarthogPaymentProcessingConfigExtra.cs b/src/Miningcore/Blockchain/Warthog/Configuration/WarthogPaymentProcessingConfigExtra.cs new file mode 100644 index 0000000000..a184825cd8 --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/Configuration/WarthogPaymentProcessingConfigExtra.cs @@ -0,0 +1,33 @@ +namespace Miningcore.Blockchain.Warthog.Configuration; + +public class WarthogPaymentProcessingConfigExtra +{ + /// + /// DANGER: The privateKey of your wallet is a very sensitive data, since it can be used for restoring the wallet, please keep it very private at all cost + /// MANDATORY for sending payments + /// + public string WalletPrivateKey { get; set; } + + /// + /// Maximum amount you're willing to pay for transaction fees (in UNIT) + /// Default: 1 + /// + public decimal? MaximumTransactionFees { get; set; } + + /// + /// True to exempt transaction fees from miner rewards + /// + public bool KeepTransactionFees { get; set; } + + /// + /// Minimum block confirmations + /// Default: "Mainnet" (120) - "Testnet" (110) + /// + public int? MinimumConfirmations { get; set; } + + /// + /// Maximum number of payouts which can be done in parallel + /// Default: 2 + /// + public int? MaxDegreeOfParallelPayouts { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Warthog/Configuration/WarthogPoolConfigExtra.cs b/src/Miningcore/Blockchain/Warthog/Configuration/WarthogPoolConfigExtra.cs new file mode 100644 index 0000000000..4b1bcc168e --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/Configuration/WarthogPoolConfigExtra.cs @@ -0,0 +1,14 @@ +using Miningcore.Configuration; + +namespace Miningcore.Blockchain.Warthog.Configuration; + +public class WarthogPoolConfigExtra +{ + /// + /// Maximum number of tracked jobs. + /// Default: 4 + /// + public int? MaxActiveJobs { get; set; } + + public int? ExtraNonce1Size { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Warthog/DaemonRequests/SendTransactionRequest.cs b/src/Miningcore/Blockchain/Warthog/DaemonRequests/SendTransactionRequest.cs new file mode 100644 index 0000000000..9bc660d561 --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/DaemonRequests/SendTransactionRequest.cs @@ -0,0 +1,24 @@ +using System.Text.Json.Serialization; + +namespace Miningcore.Blockchain.Warthog.DaemonRequests; + +public class WarthogSendTransactionRequest +{ + [JsonPropertyName("pinHeight")] + public uint PinHeight { get; set; } + + [JsonPropertyName("nonceId")] + public uint NonceId { get; set; } + + [JsonPropertyName("toAddr")] + public string ToAddress { get; set; } + + [JsonPropertyName("amountE8")] + public ulong Amount { get; set; } + + [JsonPropertyName("feeE8")] + public ulong Fee { get; set; } + + [JsonPropertyName("signature65")] + public string Signature { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Warthog/DaemonRequests/SubmitBlockRequest.cs b/src/Miningcore/Blockchain/Warthog/DaemonRequests/SubmitBlockRequest.cs new file mode 100644 index 0000000000..9ef9a3e77b --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/DaemonRequests/SubmitBlockRequest.cs @@ -0,0 +1,8 @@ +namespace Miningcore.Blockchain.Warthog.DaemonRequests; + +public class WarthogSubmitBlockRequest +{ + public uint Height { get; set; } + public string Header { get; set; } + public string Body { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetBalance.cs b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetBalance.cs new file mode 100644 index 0000000000..054bcabf50 --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetBalance.cs @@ -0,0 +1,19 @@ +using System.Text.Json.Serialization; + +namespace Miningcore.Blockchain.Warthog.DaemonResponses; + +public class WarthogBalanceData +{ + [JsonPropertyName("accountId")] + public ulong AccountId { get; set; } + + public string Address { get; set; } + + [JsonPropertyName("balanceE8")] + public ulong Balance { get; set; } +} + +public class WarthogBalance : WarthogResponseBase +{ + public WarthogBalanceData Data { get; set; } +} diff --git a/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetBlockResponse.cs b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetBlockResponse.cs new file mode 100644 index 0000000000..366ae4f23f --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetBlockResponse.cs @@ -0,0 +1,85 @@ +using System.Text.Json.Serialization; + +namespace Miningcore.Blockchain.Warthog.DaemonResponses; + +public class WarthogBlockDataBodyBlockReward +{ + [JsonPropertyName("amountE8")] + public ulong Amount { get; set; } + + [JsonPropertyName("toAddress")] + public string ToAddress { get; set; } + + /// + /// Publically searchable transaction hash + /// + [JsonPropertyName("txHash")] + public string TxHash { get; set; } +} + +public class WarthogBlockDataBody +{ + [JsonPropertyName("rewards")] + public WarthogBlockDataBodyBlockReward[] BlockReward { get; set; } +} + +public class WarthogBlockDataTransaction +{ + [JsonPropertyName("amountE8")] + public ulong Amount { get; set; } + + [JsonPropertyName("feeE8")] + public ulong Fee { get; set; } + + [JsonPropertyName("fromAddress")] + public string FromAddress { get; set; } + + [JsonPropertyName("nonceId")] + public uint NonceId { get; set; } + + [JsonPropertyName("pinHeight")] + public uint PinHeight { get; set; } + + [JsonPropertyName("toAddress")] + public string ToAddress { get; set; } + + /// + /// Publically searchable transaction hash + /// + [JsonPropertyName("txHash")] + public string TxHash { get; set; } +} + +public class WarthogBlockDataHeader +{ + public double Difficulty { get; set; } + public string Hash { get; set; } + + [JsonPropertyName("merkleroot")] + public string MerkleRoot { get; set; } + + public string Nonce { get; set; } + + [JsonPropertyName("prevHash")] + public string PrevHash { get; set; } + + public string Raw { get; set; } + public string Target { get; set; } + public ulong Timestamp { get; set; } + public string Version { get; set; } +} + +public class WarthogBlockData +{ + public WarthogBlockDataBody Body { get; set; } + public WarthogBlockDataTransaction[] Transaction { get; set; } + public ulong confirmations { get; set; } + public WarthogBlockDataHeader Header { get; set; } + public uint Height { get; set; } + public ulong timestamp { get; set; } +} + +public class WarthogBlock : WarthogResponseBase +{ + public WarthogBlockData Data { get; set; } +} diff --git a/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetBlockTemplateResponse.cs b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetBlockTemplateResponse.cs new file mode 100644 index 0000000000..bec3b419e5 --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetBlockTemplateResponse.cs @@ -0,0 +1,28 @@ +using System.Text.Json.Serialization; + +namespace Miningcore.Blockchain.Warthog.DaemonResponses; + +public class WarthogBlockTemplateData +{ + [JsonPropertyName("blockRewardE8")] + public ulong BlockReward { get; set; } + + public string Body { get; set; } + public double Difficulty { get; set; } + public string Header { get; set; } + public uint Height { get; set; } + + [JsonPropertyName("merklePrefix")] + public string MerklePrefix { get; set; } + + public bool Synced { get; set; } + public bool Testnet { get; set; } + + [JsonPropertyName("totalTxFeeE8")] + public ulong TotalTxFee { get; set; } +} + +public class WarthogBlockTemplate : WarthogResponseBase +{ + public WarthogBlockTemplateData Data { get; set; } +} diff --git a/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetChainInfoResponse.cs b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetChainInfoResponse.cs new file mode 100644 index 0000000000..7035b3d32f --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetChainInfoResponse.cs @@ -0,0 +1,30 @@ +using System.Text.Json.Serialization; + +namespace Miningcore.Blockchain.Warthog.DaemonResponses; + +public class GetChainInfoData +{ + public double Difficulty { get; set; } + public string Hash { get; set; } + public uint Height { get; set; } + + [JsonPropertyName("is_janushash")] + public bool IsJanusHash { get; set; } + + [JsonPropertyName("pinHash")] + public string PinHash { get; set; } + + [JsonPropertyName("pinHeight")] + public uint PinHeight { get; set; } + + public bool Synced { get; set; } + public double Worksum { get; set; } + + [JsonPropertyName("worksumHex")] + public string WorksumHex { get; set; } +} + +public class GetChainInfoResponse : WarthogResponseBase +{ + public GetChainInfoData Data { get; set; } +} diff --git a/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetFeeE8EncodedResponse.cs b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetFeeE8EncodedResponse.cs new file mode 100644 index 0000000000..a6d53f108f --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetFeeE8EncodedResponse.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; + +namespace Miningcore.Blockchain.Warthog.DaemonResponses; + +public class WarthogFeeE8EncodedData +{ + [JsonPropertyName("roundedE8")] + public ulong Rounded { get; set; } +} + +public class WarthogFeeE8EncodedResponse : WarthogResponseBase +{ + public WarthogFeeE8EncodedData Data { get; set; } +} diff --git a/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetNetworkHashrateResponse.cs b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetNetworkHashrateResponse.cs new file mode 100644 index 0000000000..8bbd52cdc9 --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetNetworkHashrateResponse.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace Miningcore.Blockchain.Warthog.DaemonResponses; + +public class GetNetworkHashrateData +{ + [JsonPropertyName("lastNBlocksEstimate")] + public double Hashrate { get; set; } +} + +public class GetNetworkHashrateResponse : WarthogResponseBase +{ + public GetNetworkHashrateData Data { get; set; } +} + diff --git a/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetPeersResponse.cs b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetPeersResponse.cs new file mode 100644 index 0000000000..cc967da1b0 --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetPeersResponse.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; + +namespace Miningcore.Blockchain.Warthog.DaemonResponses; + +public class GetPeersChain +{ + [JsonPropertyName("length")] + public ulong Height { get; set; } +} + +public class GetPeersResponse +{ + public GetPeersChain Chain { get; set; } +} diff --git a/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetWalletResponse.cs b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetWalletResponse.cs new file mode 100644 index 0000000000..6ee793a2d1 --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/DaemonResponses/GetWalletResponse.cs @@ -0,0 +1,19 @@ +using System.Text.Json.Serialization; + +namespace Miningcore.Blockchain.Warthog.DaemonResponses; + +public class WarthogWalletData +{ + public string Address { get; set; } + + [JsonPropertyName("privKey")] + public string PrivateKey { get; set; } + + [JsonPropertyName("pubKey")] + public string PublicKey { get; set; } +} + +public class WarthogWalletResponse : WarthogResponseBase +{ + public WarthogWalletData Data { get; set; } +} diff --git a/src/Miningcore/Blockchain/Warthog/DaemonResponses/SendTransactionResponse.cs b/src/Miningcore/Blockchain/Warthog/DaemonResponses/SendTransactionResponse.cs new file mode 100644 index 0000000000..152708f695 --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/DaemonResponses/SendTransactionResponse.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; + +namespace Miningcore.Blockchain.Warthog.DaemonResponses; + +public class WarthogSendTransactionData +{ + [JsonPropertyName("txHash")] + public string TxHash { get; set; } +} + +public class WarthogSendTransactionResponse : WarthogResponseBase +{ + public WarthogSendTransactionData Data { get; set; } +} diff --git a/src/Miningcore/Blockchain/Warthog/DaemonResponses/SubmitBlockResponse.cs b/src/Miningcore/Blockchain/Warthog/DaemonResponses/SubmitBlockResponse.cs new file mode 100644 index 0000000000..60c77582ff --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/DaemonResponses/SubmitBlockResponse.cs @@ -0,0 +1,5 @@ +namespace Miningcore.Blockchain.Warthog.DaemonResponses; + +public class WarthogSubmitBlockResponse : WarthogResponseBase +{ +} diff --git a/src/Miningcore/Blockchain/Warthog/DaemonResponses/WarthogResponseBase.cs b/src/Miningcore/Blockchain/Warthog/DaemonResponses/WarthogResponseBase.cs new file mode 100644 index 0000000000..15afa30422 --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/DaemonResponses/WarthogResponseBase.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Warthog.DaemonResponses; + +public class WarthogResponseBase +{ + [JsonProperty("code", NullValueHandling = NullValueHandling.Ignore)] + public short? Code { get; set; } + + [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)] + public string Error { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Warthog/WarthogConstants.cs b/src/Miningcore/Blockchain/Warthog/WarthogConstants.cs new file mode 100644 index 0000000000..57eda497c5 --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/WarthogConstants.cs @@ -0,0 +1,88 @@ +// ReSharper disable InconsistentNaming + +namespace Miningcore.Blockchain.Warthog; + +public static class WarthogConstants +{ + public const string JanusMiner = "janusminer"; + + public const int ExtranoncePlaceHolderLength = 10; + public static int NonceLength = 8; + public const int TimeTolerance = 600; // in seconds + + // https://www.warthog.network/docs/developers/integrations/pools/stratum/#miningset_difficulty + // In contrast to Bitcoin's stratum protocol the target is just the inverse of the difficulty. In Bitcoin there is an additional factor of 2^32 involved for historical reasons. + // Since Warthog was written from scratch, it does not carry this historical burden. This means the miner must meet the target 1/difficulty to mine a share. + public static readonly double Diff1 = 1; + + public const byte GenesisDifficultyExponent = 32; + public const uint HardestTargetHost = 0xFF800000u; + public const uint GenesisTargetHost = (uint)(GenesisDifficultyExponent << 24) | 0x00FFFFFFu; + public const uint JanusHashMaxTargetHost = 0xe00fffffu; + public const byte JanusHashMinDiffExponent = 22; + public static readonly double Pow2x1 = Math.Pow(2, 1); + public const uint JanusHashMinTargetHost = (uint)(JanusHashMinDiffExponent << 24) | 0x003FFFFFu; + + public const uint NewMerkleRootBlockHeight = 900000; + public const uint JanusHashRetargetBlockHeight = 745200; + public const uint JanusHashV2RetargetBlockHeight = 769680; + public const uint JanusHashV3RetargetBlockHeight = 776880; + public const uint JanusHashV4RetargetBlockHeight = 809280; + public const uint JanusHashV5RetargetBlockHeight = 855000; + public const uint JanusHashV6RetargetBlockHeight = 879500; + public const uint JanusHashV7RetargetBlockHeight = 987000; + + public static readonly WarthogCustomFloat ProofOfBalancedWorkC = new WarthogCustomFloat(-7, 2748779069, true); // 0.005 + public static readonly WarthogCustomFloat ProofOfBalancedWorkExponent = new WarthogCustomFloat(0, 3006477107, true); // = 0.7 <-- this can be decreased if necessary + + public const byte HeaderOffsetPrevHash = 0; + public const byte HeaderOffsetTarget = 32; + public const byte HeaderOffsetMerkleRoot = 36; + public const byte HeaderOffsetVersion = 68; + public const byte HeaderOffsetTimestamp = 72; + public const byte HeaderOffsetNonce = 76; + public const byte HeaderByteSize = 80; + + // WART smallest unit is called UNIT: https://github.com/warthog-network/Warthog/blob/master/src/shared/src/general/params.hpp#L5 + public const decimal SmallestUnit = 100000000; + + // Amount in UNIT + public const decimal MinimumTransactionFees = 1; + + public const byte PinHeightNonceIdFeeByteSize = 19; + public const byte Zero = 0; + public const byte ToAddressOffset = 20; + public const byte AmountByteSize = 8; + public const byte FullSignatureByteSize = 65; +} + +public static class WarthogCommands +{ + public const string DaemonName = "wart-node"; + public const string DataLabel = ":data:"; + + public const string Websocket = "subscribe"; + public const string WebsocketEventBlockAppend = "blockAppend"; + public const string WebsocketEventRollback = "rollback"; + + public const string GetChainInfo = "/chain/head"; + public const string GetPeers = "/peers/connected"; + public const string GetNetworkHashrate = "/chain/hashrate/" + DataLabel; + public const string GetBlockTemplate = "/chain/mine/" + DataLabel; + + public const string SubmitBlock = "/chain/append"; + + public const string GetBlockByHeight = "/chain/block/" + DataLabel; + + public const string GetWallet = "/tools/wallet/from_privkey/" + DataLabel; + public const string GetBalance = "/account/" + DataLabel + "/balance"; + public const string GetTransaction = "/transaction/lookup/" + DataLabel; + public const string SendTransaction = "/transaction/add"; + public const string GetFeeE8Encoded = "/tools/encode16bit/from_e8/" + DataLabel; +} + +public enum WarthogNetworkType +{ + Testnet, + Mainnet, +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Warthog/WarthogExtraNonceProvider.cs b/src/Miningcore/Blockchain/Warthog/WarthogExtraNonceProvider.cs new file mode 100644 index 0000000000..ffc736f8ee --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/WarthogExtraNonceProvider.cs @@ -0,0 +1,8 @@ +namespace Miningcore.Blockchain.Warthog; + +public class WarthogExtraNonceProvider : ExtraNonceProviderBase +{ + public WarthogExtraNonceProvider(string poolId, int size, byte? clusterInstanceId) : base(poolId, size, clusterInstanceId) + { + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Warthog/WarthogJob.cs b/src/Miningcore/Blockchain/Warthog/WarthogJob.cs new file mode 100644 index 0000000000..be5a00c899 --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/WarthogJob.cs @@ -0,0 +1,340 @@ +using System; +using System.Collections.Concurrent; +using System.Globalization; +using System.Linq; +using System.Text; +using VeruscoinConstants = Miningcore.Blockchain.Equihash.VeruscoinConstants; +using Miningcore.Blockchain.Warthog.DaemonResponses; +using Miningcore.Contracts; +using Miningcore.Crypto; +using Miningcore.Crypto.Hashing.Algorithms; +using Miningcore.Extensions; +using Miningcore.Native; +using Miningcore.Stratum; +using Miningcore.Time; + +namespace Miningcore.Blockchain.Warthog; + +public class WarthogJob +{ + protected IMasterClock clock; + protected readonly IHashAlgorithm sha256S = new Sha256S(); + protected readonly IHashAlgorithm sha256D = new Sha256D(); + protected readonly Verushash verusHash = new Verushash(); + + protected readonly ConcurrentDictionary submissions = new(StringComparer.OrdinalIgnoreCase); + protected WarthogTarget blockTargetValue; + protected byte[] prevHashBytes; + protected byte[] merklePrefixBytes; + //protected byte[] merkleRootBytes; + protected byte[] versionBytes; + protected byte[] nBitsBytes; + protected byte[] nTimeBytes; + + protected object[] jobParams; + + #region API-Surface + + public WarthogBlockTemplate BlockTemplate { get; protected set; } + public string PrevHash { get; protected set; } + public double Difficulty { get; protected set; } + public WarthogNetworkType network { get; protected set; } + public bool IsJanusHash { get; protected set; } + + public string JobId { get; protected set; } + + protected virtual byte[] SerializeHeader(byte[] extraNonce, uint nTime, uint nonce) + { + var merkleRootBytes = SerializeMerkleRoot(extraNonce); + + using(var stream = new MemoryStream(WarthogConstants.HeaderByteSize)) + { + var bw = new BinaryWriter(stream); + + bw.Write(prevHashBytes); + bw.Write(nBitsBytes); + bw.Write(merkleRootBytes); + bw.Write(versionBytes); + bw.Write((BitConverter.IsLittleEndian ? BitConverter.GetBytes(nTime).ReverseInPlace() : BitConverter.GetBytes(nTime))); // wart-node expects a big endian format. + bw.Write((BitConverter.IsLittleEndian ? BitConverter.GetBytes(nonce).ReverseInPlace() : BitConverter.GetBytes(nonce))); // wart-node expects a big endian format. + + return stream.ToArray(); + } + } + + protected virtual byte[] SerializeMerkleRoot(byte[] extraNonce) + { + // Merkle root computation + Span merklePrefixExtraNonceBytes = stackalloc byte[merklePrefixBytes.Length + extraNonce.Length]; + merklePrefixBytes.CopyTo(merklePrefixExtraNonceBytes); + extraNonce.CopyTo(merklePrefixExtraNonceBytes[merklePrefixBytes.Length..]); + + Span merkleRootBytes = stackalloc byte[32]; + sha256S.Digest(merklePrefixExtraNonceBytes, merkleRootBytes); + + return merkleRootBytes.ToArray(); + } + + protected virtual byte[] SerializeExtranonce(string extraNonce1, string extraNonce2) + { + var extraNonce1Bytes = extraNonce1.HexToByteArray(); + var extraNonce2Bytes = extraNonce2.HexToByteArray(); + + Span extraNonceBytes = stackalloc byte[extraNonce1Bytes.Length + extraNonce2Bytes.Length]; + extraNonce1Bytes.CopyTo(extraNonceBytes); + extraNonce2Bytes.CopyTo(extraNonceBytes[extraNonce1Bytes.Length..]); + + return extraNonceBytes.ToArray(); + } + + protected virtual byte[] SerializeBody(byte[] extraNonce) + { + var bodyBytes = BlockTemplate.Data.Body.HexToByteArray(); + var bodyBytesLength = bodyBytes.Length; + bodyBytes = bodyBytes.Skip(extraNonce.Length).Take(bodyBytesLength - extraNonce.Length).ToArray(); + + Span extraNonceBodyBytes = stackalloc byte[extraNonce.Length + bodyBytes.Length]; + extraNonce.CopyTo(extraNonceBodyBytes); + bodyBytes.CopyTo(extraNonceBodyBytes[extraNonce.Length..]); + + return extraNonceBodyBytes.ToArray(); + } + + protected virtual (Share Share, string HeaderHex) ProcessShareInternal( + StratumConnection worker, string extraNonce2, uint nTime, uint nonce) + { + var context = worker.ContextAs(); + var extraNonceBytes = SerializeExtranonce(context.ExtraNonce1, extraNonce2); + var headerSolutionBytes = SerializeHeader(extraNonceBytes, nTime, nonce); + + WarthogCustomFloat headerSolutionValue; + bool isBlockCandidate; + uint version = uint.Parse(versionBytes.ToHexString(), NumberStyles.HexNumber); + string verusHashVersion = version > 2 ? VeruscoinConstants.HashVersion2b2o : VeruscoinConstants.HashVersion2b1; + + // hash block-header with sha256D + Span headerSolutionSha256D = stackalloc byte[32]; + sha256D.Digest(headerSolutionBytes, headerSolutionSha256D); + + // hash block-header with sha256S + Span headerSolutionSha256T = stackalloc byte[32]; + sha256S.Digest(headerSolutionSha256D, headerSolutionSha256T); + + WarthogCustomFloat sha256TFloat = new WarthogCustomFloat(headerSolutionSha256T); + + // hash block-header with Verushash + Span headerSolutionVerusHash = stackalloc byte[32]; + verusHash.Digest(headerSolutionBytes, headerSolutionVerusHash, verusHashVersion); + + WarthogCustomFloat verusFloat = new WarthogCustomFloat(headerSolutionVerusHash); + + // I know the following looks incredibly overwhelming but it's the harsh reality about WARTHOG. And CODE is LAW, so we must follow it. + // https://github.com/warthog-network/Warthog/blob/master/src/shared/src/block/header/view.cpp + // Testnet + if(network == WarthogNetworkType.Testnet) + { + // The Sha256t hash must not be too small. We will adjust that if better miner(s) are available + if(sha256TFloat < WarthogConstants.ProofOfBalancedWorkC) + sha256TFloat = WarthogConstants.ProofOfBalancedWorkC; + + headerSolutionValue = verusFloat * WarthogCustomFloat.Pow(sha256TFloat, WarthogConstants.ProofOfBalancedWorkExponent); + + // check if the share meets the much harder block difficulty (block candidate) + isBlockCandidate = headerSolutionValue < blockTargetValue; + } + // Mainnet + else + { + // JanusHash activated + if(IsJanusHash && BlockTemplate.Data.Height > WarthogConstants.JanusHashRetargetBlockHeight) + { + // new JanusHash + if(BlockTemplate.Data.Height > WarthogConstants.JanusHashV2RetargetBlockHeight) + { + if(BlockTemplate.Data.Height > WarthogConstants.JanusHashV6RetargetBlockHeight) + { + // The Sha256t hash must not be too small. We will adjust that if better miner(s) are available + if(sha256TFloat < WarthogConstants.ProofOfBalancedWorkC) + sha256TFloat = WarthogConstants.ProofOfBalancedWorkC; + } + + headerSolutionValue = verusFloat * WarthogCustomFloat.Pow(sha256TFloat, WarthogConstants.ProofOfBalancedWorkExponent); + } + // old JanusHash + else + headerSolutionValue = verusFloat * sha256TFloat; + + // check if the share meets the much harder block difficulty (block candidate) + isBlockCandidate = headerSolutionValue < blockTargetValue; + } + // JanusHash not activated + else + { + headerSolutionValue = verusFloat * WarthogCustomFloat.Pow(sha256TFloat, WarthogConstants.ProofOfBalancedWorkExponent); + + // check if the share meets the much harder block difficulty (block candidate) + isBlockCandidate = headerSolutionSha256D < blockTargetValue; + } + } + + // Miner must meet the target "1/difficulty" or "1/janush_number" to mine a share - https://www.warthog.network/docs/developers/integrations/pools/stratum/#notable-differences-from-bitcoins-stratum-protocol-1 + // calc share-diff + var shareDiff = WarthogConstants.Diff1 / (double)headerSolutionValue; + + //throw new StratumException(StratumError.LowDifficultyShare, $"nonce: {nonce} - headerSolutionBytes: {headerSolutionBytes.ToHexString()} - headerSolutionVerusHash: {headerSolutionVerusHash.ToHexString()} - proofOfBalancedWorkC: {(double)WarthogConstants.ProofOfBalancedWorkC} - ProofOfBalancedWorkExponent: {(double)WarthogConstants.ProofOfBalancedWorkExponent} - sha256TFloat: {(double)sha256TFloat} - verusFloat: {(double)verusFloat} - CalculateHashrate: {WarthogUtils.CalculateHashrate(sha256TFloat, verusFloat)} ||| headerSolutionValue: {(double)headerSolutionValue} - exponent => (wcf: [{headerSolutionValue._exponent}, {(uint)(headerSolutionValue._exponent < 0 ? -headerSolutionValue._exponent : headerSolutionValue._exponent)}]), mantissa => (wcf: {headerSolutionValue._mantissa}) [stratum: {new WarthogTarget(context.Difficulty, IsJanusHash).data} - exponent => (wt: {new WarthogTarget(context.Difficulty, IsJanusHash).Zeros10()}), mantissa => (wt: {(new WarthogTarget(context.Difficulty, IsJanusHash).Bits22() << 10)}) - validShare: {(headerSolutionValue < new WarthogTarget(context.Difficulty, IsJanusHash))} - blockTemplate: {blockTargetValue.data} - exponent => (wt: {blockTargetValue.Zeros10()}), mantissa => (wt: {(blockTargetValue.Bits22() << 10)}) - blockCandidate: {isBlockCandidate}] ||| shareDiff: {shareDiff} [stratum: {context.Difficulty} - blockTemplate: {Difficulty}]"); + + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; + + // test if share meets at least workers current difficulty + 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) + { + ratio = shareDiff / context.PreviousDifficulty.Value; + + if(ratio < 0.99) + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + + // use previous difficulty + stratumDifficulty = context.PreviousDifficulty.Value; + } + + else + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + } + + var result = new Share + { + BlockHeight = BlockTemplate.Data.Height, + NetworkDifficulty = Difficulty, + Difficulty = stratumDifficulty, + }; + + if(isBlockCandidate) + { + result.IsBlockCandidate = true; + + result.BlockHash = headerSolutionSha256D.ToHexString(); + + var headerHex = headerSolutionBytes.ToHexString(); + + var extranonceBodyBytes = SerializeBody(extraNonceBytes); + BlockTemplate.Data.Body = extranonceBodyBytes.ToHexString(); + + return (result, headerHex); + } + + return (result, null); + } + + protected virtual byte[] SerializeBlock(byte[] header) + { + var height = BlockTemplate.Data.Height; + var bodyBytes = BlockTemplate.Data.Body.HexToByteArray(); + + using(var stream = new MemoryStream()) + { + var bw = new BinaryWriter(stream); + + bw.Write(height); + bw.Write(header); + bw.Write(bodyBytes); + + return stream.ToArray(); + } + } + + public virtual void Init(WarthogBlockTemplate blockTemplate, string jobId, IMasterClock clock, WarthogNetworkType network, bool isJanusHash, string prevHash) + { + Contract.RequiresNonNull(blockTemplate); + Contract.RequiresNonNull(clock); + Contract.RequiresNonNull(network); + Contract.Requires(!string.IsNullOrEmpty(jobId)); + + this.clock = clock; + BlockTemplate = blockTemplate; + JobId = jobId; + + this.network = network; + IsJanusHash = isJanusHash; + + Difficulty = BlockTemplate.Data.Difficulty; + + PrevHash = prevHash; + prevHashBytes = PrevHash.HexToByteArray(); + + var headerBytes = BlockTemplate.Data.Header.HexToByteArray(); + nBitsBytes = headerBytes.Skip(WarthogConstants.HeaderOffsetTarget).Take(WarthogConstants.HeaderOffsetMerkleRoot - WarthogConstants.HeaderOffsetTarget).ToArray(); + //merkleRootBytes = headerBytes.Skip(WarthogConstants.HeaderOffsetMerkleRoot).Take(WarthogConstants.HeaderOffsetVersion - WarthogConstants.HeaderOffsetMerkleRoot).ToArray(); + versionBytes = headerBytes.Skip(WarthogConstants.HeaderOffsetVersion).Take(WarthogConstants.HeaderOffsetTimestamp - WarthogConstants.HeaderOffsetVersion).ToArray(); + nTimeBytes = headerBytes.Skip(WarthogConstants.HeaderOffsetTimestamp).Take(WarthogConstants.HeaderOffsetNonce - WarthogConstants.HeaderOffsetTimestamp).ToArray(); + + merklePrefixBytes = BlockTemplate.Data.MerklePrefix.HexToByteArray(); + + blockTargetValue = new WarthogTarget(Difficulty, IsJanusHash); + + jobParams = new object[] + { + JobId, + PrevHash, + BlockTemplate.Data.MerklePrefix, + //uint.Parse(versionBytes.ToHexString(), NumberStyles.HexNumber), + versionBytes.ToHexString(), + nBitsBytes.ToHexString(), + nTimeBytes.ToHexString(), + false + }; + } + + public virtual object GetJobParams(bool isNew) + { + jobParams[^1] = isNew; + return jobParams; + } + + protected virtual bool RegisterSubmit(string extraNonce1, string extraNonce2, string nTime, string nonce) + { + var key = new StringBuilder() + .Append(extraNonce1) + .Append(extraNonce2) // lowercase as we don't want to accept case-sensitive values as valid. + .Append(nTime) + .Append(nonce) // lowercase as we don't want to accept case-sensitive values as valid. + .ToString(); + + return submissions.TryAdd(key, true); + } + + public virtual (Share Share, string HeaderHex) ProcessShare(StratumConnection worker, + string extraNonce2, string nTime, string nonce) + { + Contract.Requires(!string.IsNullOrEmpty(extraNonce2)); + Contract.Requires(!string.IsNullOrEmpty(nTime)); + Contract.Requires(!string.IsNullOrEmpty(nonce)); + + var context = worker.ContextAs(); + + // validate nTime + if(nTime.Length != 8) + throw new StratumException(StratumError.Other, "incorrect size of ntime"); + + var nTimeInt = uint.Parse(nTime, NumberStyles.HexNumber); + if(nTimeInt < uint.Parse(nTimeBytes.ToHexString(), NumberStyles.HexNumber) || nTimeInt > ((DateTimeOffset) clock.Now).ToUnixTimeSeconds() + WarthogConstants.TimeTolerance) + throw new StratumException(StratumError.Other, "ntime out of range"); + + // validate nonce + if(nonce.Length != WarthogConstants.NonceLength) + throw new StratumException(StratumError.Other, "incorrect size of nonce"); + + var nonceInt = uint.Parse(nonce, NumberStyles.HexNumber); + + // dupe check + if(!RegisterSubmit(context.ExtraNonce1, extraNonce2, nTime, nonce)) + throw new StratumException(StratumError.DuplicateShare, "duplicate"); + + return ProcessShareInternal(worker, extraNonce2, nTimeInt, nonceInt); + } + + #endregion // API-Surface +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Warthog/WarthogJobManager.cs b/src/Miningcore/Blockchain/Warthog/WarthogJobManager.cs new file mode 100644 index 0000000000..442a73965b --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/WarthogJobManager.cs @@ -0,0 +1,584 @@ +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Text; +using Autofac; +using Miningcore.Blockchain.Warthog.Configuration; +using Miningcore.Blockchain.Warthog.DaemonRequests; +using Miningcore.Blockchain.Warthog.DaemonResponses; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.JsonRpc; +using Miningcore.Messaging; +using Miningcore.Mining; +using Miningcore.Native; +using Miningcore.Notifications.Messages; +using Miningcore.Rest; +using Miningcore.Rpc; +using Miningcore.Stratum; +using Miningcore.Time; +using Miningcore.Util; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NLog; +using Contract = Miningcore.Contracts.Contract; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Warthog; + +public class WarthogJobManager : JobManagerBase +{ + public WarthogJobManager( + IComponentContext ctx, + IMasterClock clock, + IHttpClientFactory httpClientFactory, + IMessageBus messageBus, + IExtraNonceProvider extraNonceProvider) : + base(ctx, messageBus) + { + Contract.RequiresNonNull(ctx); + Contract.RequiresNonNull(clock); + Contract.RequiresNonNull(messageBus); + Contract.RequiresNonNull(extraNonceProvider); + + this.clock = clock; + this.extraNonceProvider = extraNonceProvider; + this.httpClientFactory = httpClientFactory; + } + + private WarthogCoinTemplate coin; + private DaemonEndpointConfig[] daemonEndpoints; + private IHttpClientFactory httpClientFactory; + private SimpleRestClient restClient; + private RpcClient rpc; + private WarthogNetworkType network; + private readonly IExtraNonceProvider extraNonceProvider; + private readonly IMasterClock clock; + private WarthogPoolConfigExtra extraPoolConfig; + private WarthogPaymentProcessingConfigExtra extraPoolPaymentProcessingConfig; + protected int maxActiveJobs; + protected bool isJanusHash; + + protected async Task UpdateJob(CancellationToken ct, string via = null) + { + try + { + var blockTemplate = await restClient.Get(WarthogCommands.GetBlockTemplate.Replace(WarthogCommands.DataLabel, poolConfig.Address), ct); + if(blockTemplate?.Error != null) + return false; + + var job = currentJob; + var newHash = blockTemplate.Data.Header.HexToByteArray().AsSpan().Slice(WarthogConstants.HeaderOffsetPrevHash, WarthogConstants.HeaderOffsetTarget).ToHexString(); + var isNew = currentJob == null || + (newHash != job?.PrevHash); + + if(isNew) + { + messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Data.Height, poolConfig.Template); + + // update job + job = new WarthogJob(); + job.Init(blockTemplate, NextJobId(), clock, network, isJanusHash, newHash); + + if(via != null) + logger.Info(() => $"Detected new block {blockTemplate.Data.Height} [{via}]"); + else + logger.Info(() => $"Detected new block {blockTemplate.Data.Height}"); + + // update stats + if (job.BlockTemplate.Data.Height > BlockchainStats.BlockHeight) + { + BlockchainStats.LastNetworkBlockTime = clock.Now; + BlockchainStats.BlockHeight = (ulong) job.BlockTemplate.Data.Height; + BlockchainStats.NetworkDifficulty = job.Difficulty; + } + + currentJob = job; + } + + else + { + if(via != null) + logger.Debug(() => $"Template update {blockTemplate.Data.Height} [{via}]"); + else + logger.Debug(() => $"Template update {blockTemplate.Data.Height}"); + } + + return isNew; + } + + catch(OperationCanceledException) + { + // ignored + } + + catch(Exception ex) + { + logger.Error(ex, () => $"Error during {nameof(UpdateJob)}"); + } + + return false; + } + + private async Task UpdateNetworkStatsAsync(CancellationToken ct) + { + try + { + var responseHashrate = await restClient.Get(WarthogCommands.GetNetworkHashrate.Replace(WarthogCommands.DataLabel, "300"), ct); + if(responseHashrate?.Code == 0) + BlockchainStats.NetworkHashrate = responseHashrate.Data.Hashrate; + + var responsePeers = await restClient.Get(WarthogCommands.GetPeers, ct); + BlockchainStats.ConnectedPeers = responsePeers.Length; + } + + catch(Exception e) + { + logger.Error(e); + } + } + + protected async Task SubmitBlockAsync(Share share, string headerHex, WarthogBlockTemplate blockTemplate, CancellationToken ct) + { + Contract.RequiresNonNull(blockTemplate); + + try + { + var block = new WarthogSubmitBlockRequest + { + Height = blockTemplate.Data.Height, + Header = headerHex, + Body = blockTemplate.Data.Body + }; + + var response = await restClient.Post(WarthogCommands.SubmitBlock, block, ct); + if(response?.Error != null) + { + logger.Warn(() => $"Block {share.BlockHeight} submission failed with: {response.Error}"); + 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}: {response.Error}")); + return false; + } + + return response?.Code == 0; + } + + catch(Exception e) + { + logger.Error(e); + return false; + } + } + + protected object GetJobParamsForStratum(bool isNew) + { + var job = currentJob; + return job?.GetJobParams(isNew); + } + + public override WarthogJob GetJobForStratum() + { + var job = currentJob; + return job; + } + + #region API-Surface + + public IObservable Jobs { get; private set; } + public BlockchainStats BlockchainStats { get; } = new(); + + public WarthogCoinTemplate Coin => coin; + + public override void Configure(PoolConfig pc, ClusterConfig cc) + { + coin = pc.Template.As(); + + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); + extraPoolPaymentProcessingConfig = pc.PaymentProcessing.Extra.SafeExtensionDataAs(); + + maxActiveJobs = extraPoolConfig?.MaxActiveJobs ?? 4; + + // extract standard daemon endpoints + daemonEndpoints = pc.Daemons + .Where(x => string.IsNullOrEmpty(x.Category)) + .ToArray(); + + base.Configure(pc, cc); + } + + public object[] GetSubscriberData(StratumConnection worker) + { + Contract.RequiresNonNull(worker); + + var context = worker.ContextAs(); + var extraNonce1Size = GetExtraNonce1Size(); + + // assign unique ExtraNonce1 to worker (miner) + context.ExtraNonce1 = extraNonceProvider.Next(); + + // setup response data + var responseData = new object[] + { + context.ExtraNonce1, + WarthogConstants.ExtranoncePlaceHolderLength - extraNonce1Size, + }; + + return responseData; + } + + public int GetExtraNonce1Size() + { + return extraPoolConfig?.ExtraNonce1Size ?? 4; + } + + public virtual async ValueTask SubmitShareAsync(StratumConnection worker, object submission, + CancellationToken ct) + { + Contract.RequiresNonNull(worker); + Contract.RequiresNonNull(submission); + + if(submission is not object[] submitParams) + throw new StratumException(StratumError.Other, "invalid params"); + + var context = worker.ContextAs(); + + // extract params + var jobId = submitParams[0] as string; + var extraNonce2 = submitParams[1] as string; + var nTime = submitParams[2] as string; + var nonce = submitParams[3] as string; + + WarthogJob job; + + lock(context) + { + job = context.GetJob(jobId); + } + + if(job == null) + throw new StratumException(StratumError.JobNotFound, "job not found"); + + // validate & process + var (share, headerHex) = job.ProcessShare(worker, extraNonce2, nTime, nonce); + + // enrich share with common data + share.PoolId = poolConfig.Id; + share.IpAddress = worker.RemoteEndpoint.Address.ToString(); + share.Miner = context.Miner; + share.Worker = context.Worker; + share.UserAgent = context.UserAgent; + share.Source = clusterConfig.ClusterName; + share.Created = clock.Now; + + // if block candidate, submit & check if accepted by network + if(share.IsBlockCandidate) + { + logger.Info(() => $"Submitting block {share.BlockHeight} [{share.BlockHash}][{headerHex}]"); + + var acceptResponse = await SubmitBlockAsync(share, headerHex, job.BlockTemplate, ct); + + // is it still a block candidate? + share.IsBlockCandidate = acceptResponse; + + if(share.IsBlockCandidate) + { + logger.Info(() => $"Daemon accepted block {share.BlockHeight} [{share.BlockHash}] submitted by {context.Miner}"); + + OnBlockFound(); + + // persist the nonce to make block unlocking a bit more reliable + share.TransactionConfirmationData = nonce; + } + + else + { + // clear fields that no longer apply + share.TransactionConfirmationData = null; + } + } + + return share; + } + + public async Task ValidateAddressAsync(string address, CancellationToken ct) + { + if(string.IsNullOrEmpty(address)) + return false; + + try + { + var response = await restClient.Get(WarthogCommands.GetBlockTemplate.Replace(WarthogCommands.DataLabel, address), ct); + if(response?.Error != null) + { + logger.Warn(() => $"'{address}': {response.Error} (Code {response?.Code})"); + return false; + } + + return response?.Code == 0; + } + + catch(Exception) + { + logger.Warn(() => $"'{WarthogCommands.DaemonName}' daemon does not seem to be running..."); + return false; + } + } + + #endregion // API-Surface + + #region Overrides + + protected override void ConfigureDaemons() + { + var jsonSerializerSettings = ctx.Resolve(); + + restClient = new SimpleRestClient(httpClientFactory, "http://" + daemonEndpoints.First().Host.ToString() + ":" + daemonEndpoints.First().Port.ToString()); + rpc = new RpcClient(daemonEndpoints.First(), jsonSerializerSettings, messageBus, poolConfig.Id); + } + + protected override async Task AreDaemonsHealthyAsync(CancellationToken ct) + { + logger.Debug(() => $"Checking if '{WarthogCommands.DaemonName}' daemon is healthy..."); + + // test daemon + try + { + var response = await restClient.Get(WarthogCommands.GetChainInfo, ct); + if(response?.Error != null) + { + logger.Warn(() => $"'{WarthogCommands.GetChainInfo}': {response.Error} (Code {response?.Code})"); + return false; + } + + return response?.Code == 0; + } + + catch(Exception) + { + logger.Warn(() => $"'{WarthogCommands.DaemonName}' daemon does not seem to be running..."); + return false; + } + } + + protected override async Task AreDaemonsConnectedAsync(CancellationToken ct) + { + logger.Debug(() => $"Checking if '{WarthogCommands.DaemonName}' daemon is connected..."); + + try + { + var response = await restClient.Get(WarthogCommands.GetPeers, ct); + + if(network == WarthogNetworkType.Testnet) + return response?.Length >= 0; + else + return response?.Length > 0; + } + + catch(Exception) + { + logger.Warn(() => $"'{WarthogCommands.DaemonName}' daemon does not seem to be running..."); + return false; + } + } + + protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) + { + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(5)); + + logger.Debug(() => $"Checking if '{WarthogCommands.DaemonName}' daemon is synched..."); + + do + { + try + { + var response = await restClient.Get(WarthogCommands.GetChainInfo, ct); + if(response?.Code == null) + logger.Debug(() => $"'{WarthogCommands.DaemonName}' daemon did not responded..."); + + if(response?.Error != null) + logger.Debug(() => $"'{WarthogCommands.GetChainInfo}': {response.Error} (Code {response?.Code})"); + + if(response.Data.Synced) + { + logger.Info(() => $"'{WarthogCommands.DaemonName}' daemon synched with blockchain"); + break; + } + + logger.Info(() => $"Daemon is still syncing with network. Current height: {response?.Data.Height}. Manager will be started once synced."); + } + + catch(Exception) + { + logger.Warn(() => $"'{WarthogCommands.DaemonName}' daemon does not seem to be running..."); + } + } while(await timer.WaitForNextTickAsync(ct)); + } + + protected override async Task PostStartInitAsync(CancellationToken ct) + { + // validate pool address + if(string.IsNullOrEmpty(poolConfig.Address)) + throw new PoolStartupException("Pool address is not configured", poolConfig.Id); + + // test daemon + try + { + var responseChain = await restClient.Get(WarthogCommands.GetChainInfo, ct); + if(responseChain?.Code == null) + throw new PoolStartupException("Init RPC failed...", poolConfig.Id); + + isJanusHash = responseChain.Data.IsJanusHash; + if(isJanusHash) + logger.Info(() => "JanusHash activated"); + } + + catch(Exception) + { + logger.Warn(() => $"'{WarthogCommands.DaemonName} - {WarthogCommands.GetChainInfo}' daemon does not seem to be running..."); + throw new PoolStartupException("Init RPC failed...", poolConfig.Id); + } + + try + { + var responsePoolAddress = await restClient.Get(WarthogCommands.GetBlockTemplate.Replace(WarthogCommands.DataLabel, poolConfig.Address), ct); + if(responsePoolAddress?.Error != null) + throw new PoolStartupException($"Pool address '{poolConfig.Address}': {responsePoolAddress.Error} (Code {responsePoolAddress?.Code})", poolConfig.Id); + + network = responsePoolAddress.Data.Testnet ? WarthogNetworkType.Testnet : WarthogNetworkType.Mainnet; + + // update stats + BlockchainStats.RewardType = "POW"; + BlockchainStats.NetworkType = $"{network}"; + } + + catch(Exception) + { + logger.Warn(() => $"'{WarthogCommands.DaemonName} - {WarthogCommands.GetBlockTemplate}' daemon does not seem to be running..."); + throw new PoolStartupException($"Pool address check failed...", poolConfig.Id); + } + + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + // validate pool address privateKey + if(string.IsNullOrEmpty(extraPoolPaymentProcessingConfig?.WalletPrivateKey)) + throw new PoolStartupException("Pool address private key is not configured", poolConfig.Id); + + try + { + var responsePoolAddressWalletPrivateKey = await restClient.Get(WarthogCommands.GetWallet.Replace(WarthogCommands.DataLabel, extraPoolPaymentProcessingConfig?.WalletPrivateKey), ct); + if(responsePoolAddressWalletPrivateKey?.Error != null) + throw new PoolStartupException($"Pool address private key '{extraPoolPaymentProcessingConfig?.WalletPrivateKey}': {responsePoolAddressWalletPrivateKey.Error} (Code {responsePoolAddressWalletPrivateKey?.Code})", poolConfig.Id); + + if(responsePoolAddressWalletPrivateKey.Data.Address != poolConfig.Address) + throw new PoolStartupException($"Pool address private key '{extraPoolPaymentProcessingConfig?.WalletPrivateKey}' [{responsePoolAddressWalletPrivateKey.Data.Address}] does not match pool address: {poolConfig.Address}", poolConfig.Id); + } + + catch(Exception) + { + logger.Warn(() => $"'{WarthogCommands.DaemonName} - {WarthogCommands.GetWallet}' daemon does not seem to be running..."); + throw new PoolStartupException($"Pool address private key check failed...", poolConfig.Id); + } + } + + await UpdateNetworkStatsAsync(ct); + + // Periodically update network stats + Observable.Interval(TimeSpan.FromMinutes(1)) + .Select(via => Observable.FromAsync(() => + Guard(()=> UpdateNetworkStatsAsync(ct), + ex=> logger.Error(ex)))) + .Concat() + .Subscribe(); + + SetupJobUpdates(ct); + } + + protected virtual void SetupJobUpdates(CancellationToken ct) + { + var pollingInterval = poolConfig?.BlockRefreshInterval ?? 0; + + var blockSubmission = blockFoundSubject.Synchronize(); + var pollTimerRestart = blockFoundSubject.Synchronize(); + + var triggers = new List> + { + blockSubmission.Select(_ => (JobRefreshBy.BlockFound, (string) null)) + }; + + var endpointExtra = daemonEndpoints + .Where(x => x.Extra.SafeExtensionDataAs() != null) + .Select(x=> Tuple.Create(x, x.Extra.SafeExtensionDataAs())) + .FirstOrDefault(); + + if(endpointExtra?.Item2?.PortWs.HasValue == true) + { + var (endpointConfig, extra) = endpointExtra; + + var wsEndpointConfig = new DaemonEndpointConfig + { + Host = endpointConfig.Host, + Port = extra.PortWs!.Value, + HttpPath = extra.HttpPathWs, + Ssl = extra.SslWs + }; + + logger.Info(() => $"Subscribing to WebSocket {(wsEndpointConfig.Ssl ? "wss" : "ws")}://{wsEndpointConfig.Host}:{wsEndpointConfig.Port}"); + + // stream work updates + var getWorkObs = rpc.WebsocketSubscribe(logger, ct, wsEndpointConfig, WarthogCommands.Websocket, new[] { WarthogCommands.WebsocketEventRollback, WarthogCommands.WebsocketEventBlockAppend }) + .Publish() + .RefCount(); + + var websocketNotify = getWorkObs.Where(x => x != null) + .Publish() + .RefCount(); + + pollTimerRestart = blockSubmission.Merge(websocketNotify.Select(_ => Unit.Default)) + .Publish() + .RefCount(); + + triggers.Add(websocketNotify.Select(_ => (JobRefreshBy.WebSocket, (string) null))); + + if(pollingInterval > 0) + { + triggers.Add(Observable.Timer(TimeSpan.FromMilliseconds(pollingInterval)) + .TakeUntil(pollTimerRestart) + .Select(_ => (JobRefreshBy.Poll, (string) null)) + .Repeat()); + } + + else + { + // get initial blocktemplate + triggers.Add(Observable.Interval(TimeSpan.FromMilliseconds(1000)) + .Select(_ => (JobRefreshBy.Initial, (string) null)) + .TakeWhile(_ => !hasInitialBlockTemplate)); + } + } + + else + { + pollingInterval = pollingInterval > 0 ? pollingInterval : 1000; + + // ordinary polling (avoid this at all cost) + triggers.Add(Observable.Timer(TimeSpan.FromMilliseconds(pollingInterval)) + .TakeUntil(pollTimerRestart) + .Select(_ => (JobRefreshBy.Poll, (string) null)) + .Repeat()); + } + + Jobs = triggers.Merge() + .Select(x => Observable.FromAsync(() => UpdateJob(ct, x.Via))) + .Concat() + .Where(x => x) + .Do(x => + { + if(x) + hasInitialBlockTemplate = true; + }) + .Select(x => GetJobParamsForStratum(x)) + .Publish() + .RefCount(); + } + + #endregion // Overrides +} diff --git a/src/Miningcore/Blockchain/Warthog/WarthogPayoutHandler.cs b/src/Miningcore/Blockchain/Warthog/WarthogPayoutHandler.cs new file mode 100644 index 0000000000..c727c020ae --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/WarthogPayoutHandler.cs @@ -0,0 +1,495 @@ +using System; +using System.Linq; +using Autofac; +using AutoMapper; +using Miningcore.Blockchain.Warthog.Configuration; +using Miningcore.Blockchain.Warthog.DaemonRequests; +using Miningcore.Blockchain.Warthog.DaemonResponses; +using Miningcore.Configuration; +using Miningcore.Crypto; +using Miningcore.Crypto.Hashing.Algorithms; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Mining; +using Miningcore.Payments; +using Miningcore.Persistence; +using Miningcore.Persistence.Model; +using Miningcore.Persistence.Repositories; +using Miningcore.Rest; +using Miningcore.Time; +using Miningcore.Util; +using NBitcoin.Secp256k1; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Block = Miningcore.Persistence.Model.Block; +using Contract = Miningcore.Contracts.Contract; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Warthog; + +[CoinFamily(CoinFamily.Warthog)] +public class WarthogPayoutHandler : PayoutHandlerBase, + IPayoutHandler +{ + public WarthogPayoutHandler( + IComponentContext ctx, + IConnectionFactory cf, + IMapper mapper, + IShareRepository shareRepo, + IBlockRepository blockRepo, + IBalanceRepository balanceRepo, + IPaymentRepository paymentRepo, + IMasterClock clock, + IHttpClientFactory httpClientFactory, + IMessageBus messageBus) : + base(cf, mapper, shareRepo, blockRepo, balanceRepo, paymentRepo, clock, messageBus) + { + Contract.RequiresNonNull(ctx); + Contract.RequiresNonNull(balanceRepo); + Contract.RequiresNonNull(paymentRepo); + + this.ctx = ctx; + this.httpClientFactory = httpClientFactory; + } + + protected readonly IComponentContext ctx; + private IHttpClientFactory httpClientFactory; + private SimpleRestClient restClient; + private string network; + private WarthogPaymentProcessingConfigExtra extraPoolPaymentProcessingConfig; + private int minConfirmations; + private decimal maximumTransactionFees; + private ECPrivKey ellipticPrivateKey; + private readonly IHashAlgorithm sha256S = new Sha256S(); + private object nonceGenLock = new(); + + protected override string LogCategory => "Warthog Payout Handler"; + + #region IPayoutHandler + + public virtual async Task ConfigureAsync(ClusterConfig cc, PoolConfig pc, CancellationToken ct) + { + Contract.RequiresNonNull(pc); + + poolConfig = pc; + clusterConfig = cc; + extraPoolPaymentProcessingConfig = pc.PaymentProcessing.Extra.SafeExtensionDataAs(); + + maximumTransactionFees = extraPoolPaymentProcessingConfig?.MaximumTransactionFees ?? WarthogConstants.MinimumTransactionFees; + + logger = LogUtil.GetPoolScopedLogger(typeof(WarthogPayoutHandler), pc); + + // configure standard daemon + var jsonSerializerSettings = ctx.Resolve(); + + var daemonEndpoints = pc.Daemons + .Where(x => string.IsNullOrEmpty(x.Category)) + .ToArray(); + + restClient = new SimpleRestClient(httpClientFactory, "http://" + daemonEndpoints.First().Host.ToString() + ":" + daemonEndpoints.First().Port.ToString()); + + try + { + var response = await restClient.Get(WarthogCommands.GetBlockTemplate.Replace(WarthogCommands.DataLabel, poolConfig.Address), ct); + if(response?.Error != null) + throw new Exception($"Pool address '{poolConfig.Address}': {response.Error} (Code {response?.Code})"); + + network = response.Data.Testnet ? "testnet" : "mainnet"; + } + + catch(Exception e) + { + logger.Warn(() => $"[{LogCategory}] '{WarthogCommands.DaemonName} - {WarthogCommands.GetBlockTemplate}' daemon does not seem to be running..."); + throw new Exception($"'{WarthogCommands.DaemonName}' returned error: {e}"); + } + + if(string.IsNullOrEmpty(extraPoolPaymentProcessingConfig?.WalletPrivateKey)) + throw new Exception("WalletPrivateKey is mandatory for signing and sending transactions"); + else + { + try + { + var responsePoolAddressWalletPrivateKey = await restClient.Get(WarthogCommands.GetWallet.Replace(WarthogCommands.DataLabel, extraPoolPaymentProcessingConfig?.WalletPrivateKey), ct); + if(responsePoolAddressWalletPrivateKey?.Error != null) + throw new Exception($"Pool address private key '{extraPoolPaymentProcessingConfig?.WalletPrivateKey}': {responsePoolAddressWalletPrivateKey.Error} (Code {responsePoolAddressWalletPrivateKey?.Code})"); + + if(responsePoolAddressWalletPrivateKey.Data.Address != poolConfig.Address) + throw new Exception($"Pool address private key '{extraPoolPaymentProcessingConfig?.WalletPrivateKey}' [{responsePoolAddressWalletPrivateKey.Data.Address}] does not match pool address: {poolConfig.Address}"); + } + + catch(Exception e) + { + logger.Warn(() => $"[{LogCategory}] '{WarthogCommands.DaemonName} - {WarthogCommands.GetWallet}' daemon does not seem to be running..."); + throw new Exception($"'{WarthogCommands.DaemonName}' returned error: {e}"); + } + + ellipticPrivateKey = Context.Instance.CreateECPrivKey(extraPoolPaymentProcessingConfig.WalletPrivateKey.HexToByteArray()); + } + + minConfirmations = extraPoolPaymentProcessingConfig?.MinimumConfirmations ?? (network == "mainnet" ? 120 : 110); + } + + public virtual async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, CancellationToken ct) + { + Contract.RequiresNonNull(poolConfig); + Contract.RequiresNonNull(blocks); + + if(blocks.Length == 0) + return blocks; + + GetChainInfoResponse chainInfo; + try + { + chainInfo = await restClient.Get(WarthogCommands.GetChainInfo, ct); + if(chainInfo?.Error != null) + { + logger.Warn(() => $"[{LogCategory}] '{WarthogCommands.GetChainInfo}': {chainInfo.Error} (Code {chainInfo?.Code})"); + return blocks; + } + } + + catch(Exception) + { + logger.Warn(() => $"[{LogCategory}] '{WarthogCommands.DaemonName} - {WarthogCommands.GetChainInfo}' daemon does not seem to be running..."); + return blocks; + } + + var coin = poolConfig.Template.As(); + var pageSize = 100; + var pageCount = (int) Math.Ceiling(blocks.Length / (double) pageSize); + var result = new List(); + + for(var i = 0; i < pageCount; i++) + { + // get a page full of blocks + var page = blocks + .Skip(i * pageSize) + .Take(pageSize) + .ToArray(); + + for(var j = 0; j < page.Length; j++) + { + var block = page[j]; + + WarthogBlock response; + try + { + response = await restClient.Get(WarthogCommands.GetBlockByHeight.Replace(WarthogCommands.DataLabel, block.BlockHeight.ToString()), ct); + if(response?.Error != null) + logger.Warn(() => $"[{LogCategory}] Block {block.BlockHeight}: {response.Error} (Code {response?.Code})"); + } + + catch(Exception e) + { + logger.Warn(() => $"[{LogCategory}] '{WarthogCommands.DaemonName} - {WarthogCommands.GetBlockByHeight}' daemon does not seem to be running..."); + throw new Exception($"'{WarthogCommands.DaemonName}' returned error: {e}"); + } + + // We lost that battle + if(response?.Data.Header.Hash != block.Hash) + { + result.Add(block); + + block.Status = BlockStatus.Orphaned; + block.Reward = 0; + + logger.Info(() => $"[{LogCategory}] Block {block.BlockHeight} classified as orphaned because {(response?.Error != null ? "it's not on chain" : $"it has a different hash on chain: {response.Data.Header.Hash}")}"); + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + } + else + { + logger.Info(() => $"[{LogCategory}] Block {block.BlockHeight} uses a custom minimum confirmations calculation [{minConfirmations}]"); + + block.ConfirmationProgress = Math.Min(1.0d, (double) (chainInfo.Data.Height - block.BlockHeight) / minConfirmations); + + result.Add(block); + + messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); + + // matured and spendable? + if(block.ConfirmationProgress >= 1) + { + block.ConfirmationProgress = 1; + + logger.Debug(() => $"[{LogCategory}] Block {block.BlockHeight} contains {response.Data.Body.BlockReward.Length} block reward(s)"); + + // reset block reward + block.Reward = 0; + + // we only need the block reward(s) related to our pool address + var blockRewards = response.Data.Body.BlockReward + .Where(x => x.ToAddress.Contains(poolConfig.Address)) + .ToList(); + + foreach (var blockReward in blockRewards) + { + block.Reward += (decimal) blockReward.Amount / WarthogConstants.SmallestUnit; + } + + // security + if (block.Reward > 0) + { + block.Status = BlockStatus.Confirmed; + + logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); + } + else + { + block.Status = BlockStatus.Orphaned; + block.Reward = 0; + } + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + } + } + } + } + + return result.ToArray(); + } + + public virtual async Task PayoutAsync(IMiningPool pool, Balance[] balances, CancellationToken ct) + { + Contract.RequiresNonNull(balances); + + // build args + var amounts = balances + .Where(x => x.Amount > 0) + .ToDictionary(x => x.Address, x => x.Amount); + + if(amounts.Count == 0) + return; + + var balancesTotal = amounts.Sum(x => x.Value); + logger.Info(() => $"[{LogCategory}] Paying {FormatAmount(balancesTotal)} to {balances.Length} addresses"); + + logger.Info(() => $"[{LogCategory}] Validating addresses..."); + foreach(var pair in amounts) + { + logger.Debug(() => $"[{LogCategory}] Address {pair.Key} with amount [{FormatAmount(pair.Value)}]"); + try + { + var responseAddress = await restClient.Get(WarthogCommands.GetBlockTemplate.Replace(WarthogCommands.DataLabel, pair.Key), ct); + if(responseAddress?.Error != null) + logger.Warn(()=> $"[{LogCategory}] Address {pair.Key} is not valid: {responseAddress.Error} (Code {responseAddress?.Code})"); + } + + catch(Exception e) + { + logger.Warn(() => $"[{LogCategory}] '{WarthogCommands.DaemonName} - {WarthogCommands.GetBlockTemplate}' daemon does not seem to be running..."); + throw new Exception($"'{WarthogCommands.DaemonName}' returned error: {e}"); + } + } + + WarthogBalance responseBalance; + try + { + responseBalance = await restClient.Get(WarthogCommands.GetBalance.Replace(WarthogCommands.DataLabel, poolConfig.Address), ct); + if(responseBalance?.Error != null) + logger.Warn(()=> $"[{LogCategory}] '{WarthogCommands.GetBalance}': {responseBalance.Error} (Code {responseBalance?.Code})"); + } + + catch(Exception e) + { + logger.Warn(() => $"[{LogCategory}] '{WarthogCommands.DaemonName} - {WarthogCommands.GetBalance}' daemon does not seem to be running..."); + throw new Exception($"'{WarthogCommands.DaemonName}' returned error: {e}"); + } + + var walletBalance = (decimal) (responseBalance?.Data.Balance == null ? 0 : responseBalance?.Data.Balance) / WarthogConstants.SmallestUnit; + + logger.Info(() => $"[{LogCategory}] Current wallet balance - Total: [{FormatAmount(walletBalance)}]"); + + // bail if balance does not satisfy payments + if(walletBalance < balancesTotal) + { + logger.Warn(() => $"[{LogCategory}] Wallet balance currently short of {FormatAmount(balancesTotal - walletBalance)}. Will try again"); + return; + } + + if(extraPoolPaymentProcessingConfig?.KeepTransactionFees == true) + logger.Debug(() => $"[{LogCategory}] Pool does not pay the transaction fee, so each address will have its payout deducted with [{FormatAmount(maximumTransactionFees / WarthogConstants.SmallestUnit)}]"); + + var txFailures = new List, Exception>>(); + var successBalances = new Dictionary(); + + Random randomNonceId = new Random(); + List usedNonceId = new List(); + + var parallelOptions = new ParallelOptions + { + MaxDegreeOfParallelism = extraPoolPaymentProcessingConfig?.MaxDegreeOfParallelPayouts ?? 2, + CancellationToken = ct + }; + + await Parallel.ForEachAsync(amounts, parallelOptions, async (x, _ct) => + { + var (address, amount) = x; + + await Guard(async () => + { + uint nonceId = (uint) randomNonceId.NextInt64((long)uint.MinValue, (long)uint.MaxValue); + + lock(nonceGenLock) + { + bool IsSafeToContinue = false; + while(!IsSafeToContinue) + { + if(!(usedNonceId.Contains(nonceId))) + { + logger.Debug(()=> $"[{LogCategory}] Transaction nonceId: [{nonceId}]"); + + usedNonceId.Add(nonceId); + IsSafeToContinue = true; + } + else + nonceId = (uint) randomNonceId.NextInt64((long)uint.MinValue, (long)uint.MaxValue); + } + } + + logger.Info(()=> $"[{LogCategory}] [{nonceId}] Sending {FormatAmount(amount)} to {address}"); + + // WART payment is quite complex: https://www.warthog.network/docs/developers/integrations/wallet-integration/ - https://www.warthog.network/docs/developers/api/#post-transactionadd + var chainInfo = await restClient.Get(WarthogCommands.GetChainInfo, ct); + if(chainInfo?.Error != null) + throw new Exception($"'{WarthogCommands.GetChainInfo}': {chainInfo.Error} (Code {chainInfo?.Code})"); + + var feeE8Encoded = await restClient.Get(WarthogCommands.GetFeeE8Encoded.Replace(WarthogCommands.DataLabel, maximumTransactionFees.ToString()), ct); + if(feeE8Encoded?.Error != null) + throw new Exception($"'{WarthogCommands.GetFeeE8Encoded}': {feeE8Encoded.Error} (Code {feeE8Encoded?.Code})"); + + var amountE8 = (ulong) Math.Floor(((extraPoolPaymentProcessingConfig?.KeepTransactionFees == false) ? amount : (amount > (maximumTransactionFees / WarthogConstants.SmallestUnit) ? amount - (maximumTransactionFees / WarthogConstants.SmallestUnit) : amount)) * WarthogConstants.SmallestUnit); + + // generate bytes to sign + var pinHashBytes = chainInfo.Data.PinHash.HexToByteArray(); + var pinHeightNonceIdFeeBytes = SerializePinHeightNonceIdFee(chainInfo.Data.PinHeight, nonceId, feeE8Encoded.Data.Rounded); + var toAddressBytes = address.HexToByteArray().Take(WarthogConstants.ToAddressOffset).ToArray(); + var amountBytes = SerializeAmount(amountE8); + var signatureBytes = SerializeSignature(pinHashBytes, pinHeightNonceIdFeeBytes, toAddressBytes, amountBytes); + + // sign bytes + byte[] signatureHashBytes = new byte[32]; + sha256S.Digest(signatureBytes, (Span) signatureHashBytes); + + SecpECDSASignature signatureECDSA; + int recid; + + // this beautiful NBitcoin class automatically normalizes the signature and recid + var signedECDSA = ellipticPrivateKey.TrySignECDSA(signatureHashBytes, null, out recid, out signatureECDSA); + if(!signedECDSA || signatureECDSA == null) + throw new Exception("SignECDSA failed (bug in C# secp256k1)"); + + var fullSignatureBytes = SerializeFullSignature(signatureECDSA.r.ToBytes(), signatureECDSA.s.ToBytes(), (byte) recid); + + var sendTransaction = new WarthogSendTransactionRequest + { + PinHeight = chainInfo.Data.PinHeight, + NonceId = nonceId, + ToAddress = address, + Amount = amountE8, + Fee = feeE8Encoded.Data.Rounded, + Signature = fullSignatureBytes.ToHexString() + }; + + var response = await restClient.Post(WarthogCommands.SendTransaction, sendTransaction, ct); + if(response?.Error != null) + throw new Exception($"[{nonceId}] {WarthogCommands.SendTransaction} returned error: {response.Error} (Code {response?.Code})"); + + if(string.IsNullOrEmpty(response.Data.TxHash)) + throw new Exception($"[{nonceId}] {WarthogCommands.SendTransaction} did not return a transaction id!"); + else + logger.Info(() => $"[{LogCategory}] [{nonceId}] Payment transaction id: {response.Data.TxHash}"); + + successBalances.Add(new Balance + { + PoolId = poolConfig.Id, + Address = address, + Amount = amount, + }, response.Data.TxHash); + }, ex => + { + txFailures.Add(Tuple.Create(x, ex)); + }); + }); + + if(successBalances.Any()) + { + await PersistPaymentsAsync(successBalances); + + NotifyPayoutSuccess(poolConfig.Id, successBalances.Keys.ToArray(), successBalances.Values.ToArray(), null); + } + + if(txFailures.Any()) + { + var failureBalances = txFailures.Select(x=> new Balance { Amount = x.Item1.Value }).ToArray(); + var error = string.Join(", ", txFailures.Select(x => $"{x.Item1.Key} {FormatAmount(x.Item1.Value)}: {x.Item2.Message}")); + + logger.Error(()=> $"[{LogCategory}] Failed to transfer the following balances: {error}"); + + NotifyPayoutFailure(poolConfig.Id, failureBalances, error, null); + } + } + + public double AdjustBlockEffort(double effort) + { + return effort; + } + + #endregion // IPayoutHandler + + private byte[] SerializePinHeightNonceIdFee(uint pinHeight, uint nonceId, ulong feeE8Encoded) + { + using(var stream = new MemoryStream(WarthogConstants.PinHeightNonceIdFeeByteSize)) + { + var bw = new BinaryWriter(stream); + + bw.Write((BitConverter.IsLittleEndian ? BitConverter.GetBytes(pinHeight).ReverseInPlace() : BitConverter.GetBytes(pinHeight))); // wart-node expects a big endian format. + bw.Write((BitConverter.IsLittleEndian ? BitConverter.GetBytes(nonceId).ReverseInPlace() : BitConverter.GetBytes(nonceId))); // wart-node expects a big endian format. + bw.Write(WarthogConstants.Zero); + bw.Write(WarthogConstants.Zero); + bw.Write(WarthogConstants.Zero); + bw.Write((BitConverter.IsLittleEndian ? BitConverter.GetBytes(feeE8Encoded).ReverseInPlace() : BitConverter.GetBytes(feeE8Encoded))); // wart-node expects a big endian format. + + return stream.ToArray(); + } + } + + private byte[] SerializeAmount(ulong amount) + { + using(var stream = new MemoryStream(WarthogConstants.AmountByteSize)) + { + var bw = new BinaryWriter(stream); + + bw.Write((BitConverter.IsLittleEndian ? BitConverter.GetBytes(amount).ReverseInPlace() : BitConverter.GetBytes(amount))); // wart-node expects a big endian format. + + return stream.ToArray(); + } + } + + private byte[] SerializeSignature(byte[] pinHashBytes, byte[] pinHeightNonceIdFeeBytes, byte[] toAddressBytes, byte[] amountBytes) + { + using(var stream = new MemoryStream()) + { + stream.Write(pinHashBytes); + stream.Write(pinHeightNonceIdFeeBytes); + stream.Write(toAddressBytes); + stream.Write(amountBytes); + + return stream.ToArray(); + } + } + + private byte[] SerializeFullSignature(byte[] rBytes, byte[] sBytes, byte recid) + { + using(var stream = new MemoryStream(WarthogConstants.FullSignatureByteSize)) + { + var bw = new BinaryWriter(stream); + + bw.Write(rBytes); + bw.Write(sBytes); + bw.Write(recid); // wart-node expects a big endian format. + + return stream.ToArray(); + } + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Warthog/WarthogPool.cs b/src/Miningcore/Blockchain/Warthog/WarthogPool.cs new file mode 100644 index 0000000000..417d90db4b --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/WarthogPool.cs @@ -0,0 +1,431 @@ +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using Autofac; +using AutoMapper; +using Microsoft.IO; +using Miningcore.Blockchain.Bitcoin; +using Miningcore.Blockchain.Warthog; +using Miningcore.Blockchain.Warthog.Configuration; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.JsonRpc; +using Miningcore.Messaging; +using Miningcore.Mining; +using Miningcore.Nicehash; +using Miningcore.Notifications.Messages; +using Miningcore.Persistence; +using Miningcore.Persistence.Repositories; +using Miningcore.Stratum; +using Miningcore.Time; +using Newtonsoft.Json; +using NLog; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Warthog; + +[CoinFamily(CoinFamily.Warthog)] +public class WarthogPool : PoolBase +{ + public WarthogPool(IComponentContext ctx, + JsonSerializerSettings serializerSettings, + IConnectionFactory cf, + IStatsRepository statsRepo, + IMapper mapper, + IMasterClock clock, + IMessageBus messageBus, + RecyclableMemoryStreamManager rmsm, + NicehashService nicehashService) : + base(ctx, serializerSettings, cf, statsRepo, mapper, clock, messageBus, rmsm, nicehashService) + { + } + + private object currentJobParams; + private WarthogJobManager manager; + private WarthogPoolConfigExtra extraPoolConfig; + private WarthogCoinTemplate coin; + + protected virtual async Task OnSubscribeAsync(StratumConnection connection, Timestamped tsRequest) + { + var request = tsRequest.Value; + + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + var context = connection.ContextAs(); + + var requestParams = request.ParamsAs(); + + if(requestParams?.Length < 1) + throw new StratumException(StratumError.Other, "invalid params"); + + context.UserAgent = requestParams.FirstOrDefault()?.Trim(); + + var subscriberData = manager.GetSubscriberData(connection); + var data = new object[] + { + new object[] + { + new object[] { BitcoinStratumMethods.MiningNotify, connection.ConnectionId } + } + } + .Concat(subscriberData) + .ToArray(); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(data, request.Id); + + if(context.IsNicehash || context.UserAgent.Contains(WarthogConstants.JanusMiner)) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); + + // setup worker context + context.IsSubscribed = true; + + // Nicehash support + var nicehashDiff = await GetNicehashStaticMinDiff(context, coin.Name, coin.GetAlgorithmName()); + + if(nicehashDiff.HasValue) + { + logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using API supplied difficulty of {nicehashDiff.Value}"); + + context.VarDiff = null; // disable vardiff + context.SetDifficulty(nicehashDiff.Value); + } + } + + protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + var context = connection.ContextAs(); + if(!context.IsSubscribed) + throw new StratumException(StratumError.NotSubscribed, "subscribe first please, we aren't savages"); + + var requestParams = request.ParamsAs(); + + if(requestParams?.Length < 1) + throw new StratumException(StratumError.Other, "invalid params"); + + var workerValue = requestParams?.Length > 0 ? requestParams[0] : null; + var password = requestParams?.Length > 1 ? requestParams[1] : null; + var passParts = password?.Split(PasswordControlVarsSeparator); + + // extract worker/miner + var split = workerValue?.Split('.'); + var minerName = split?.FirstOrDefault()?.Trim(); + var workerName = split?.Skip(1).FirstOrDefault()?.Trim() ?? string.Empty; + + // assumes that minerName is an address + context.IsAuthorized = await manager.ValidateAddressAsync(minerName, ct); + context.Miner = minerName; + context.Worker = workerName; + + if(context.IsAuthorized) + { + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(context.IsAuthorized, request.Id); + + if(context.IsNicehash || context.UserAgent.Contains(WarthogConstants.JanusMiner)) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + // respond + await connection.RespondAsync(response); + + // log association + logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); + + // extract control vars from password + var staticDiff = GetStaticDiffFromPassparts(passParts); + + // Static diff + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) + { + context.VarDiff = null; // disable vardiff + context.SetDifficulty(staticDiff.Value); + + logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); + } + + var minerJobParams = CreateWorkerJob(connection, context.IsAuthorized); + + // send intial update + await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); + } + + else + { + await connection.RespondErrorAsync(StratumError.UnauthorizedWorker, "Authorization failed", request.Id, context.IsAuthorized); + + if(clusterConfig?.Banning?.BanOnLoginFailure is null or true) + { + // issue short-time ban if unauthorized to prevent DDos on daemon (validateaddress RPC) + logger.Info(() => $"[{connection.ConnectionId}] Banning unauthorized worker {minerName} for {loginFailureBanTimeout.TotalSeconds} sec"); + + banManager.Ban(connection.RemoteEndpoint.Address, loginFailureBanTimeout); + + Disconnect(connection); + } + } + } + + private object CreateWorkerJob(StratumConnection connection, bool cleanJob) + { + var context = connection.ContextAs(); + var maxActiveJobs = extraPoolConfig?.MaxActiveJobs ?? 4; + var job = manager.GetJobForStratum(); + + // update context + lock(context) + { + context.AddJob(job, maxActiveJobs); + } + + return job.GetJobParams(cleanJob); + } + + protected virtual async Task OnSubmitAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + try + { + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + // check age of submission (aged submissions are usually caused by high server load) + var requestAge = clock.Now - tsRequest.Timestamp.UtcDateTime; + + if(requestAge > maxShareAge) + { + logger.Warn(() => $"[{connection.ConnectionId}] Dropping stale share submission request (server overloaded?)"); + return; + } + + // check worker state + context.LastActivity = clock.Now; + + // validate worker + if(!context.IsAuthorized) + throw new StratumException(StratumError.UnauthorizedWorker, "unauthorized worker"); + else if(!context.IsSubscribed) + throw new StratumException(StratumError.NotSubscribed, "not subscribed"); + + var requestParams = request.ParamsAs(); + + // submit + var share = await manager.SubmitShareAsync(connection, requestParams, ct); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || context.UserAgent.Contains(WarthogConstants.JanusMiner)) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + // respond + await connection.RespondAsync(response); + + // publish + messageBus.SendMessage(share); + + // telemetry + PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, true); + + logger.Info(() => $"[{connection.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty, 3)}"); + + // update pool stats + if(share.IsBlockCandidate) + poolStats.LastPoolBlockTime = clock.Now; + + // update client stats + context.Stats.ValidShares++; + + await UpdateVarDiffAsync(connection, false, ct); + } + + catch(StratumException ex) + { + // telemetry + PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, false); + + // update client stats + context.Stats.InvalidShares++; + logger.Info(() => $"[{connection.ConnectionId}] Share rejected: {ex.Message} [{context.UserAgent}]"); + + // banning + ConsiderBan(connection, context, poolConfig.Banning); + + if(context.UserAgent.Contains(WarthogConstants.JanusMiner)) + { + // Little hack to allow JanusMiner to mine on our stratum without interruptions even though we should still be able to ban it just in case + // [Respect the goddamn standards though :(] + var response = new JsonRpcResponse(true, request.Id); + response.Extra = new Dictionary(); + response.Extra["error"] = null; + + // respond + await connection.RespondAsync(response); + } + else + throw; + } + } + + protected virtual async Task OnNewJobAsync(object jobParams) + { + currentJobParams = jobParams; + + logger.Info(() => $"Broadcasting job {((object[]) jobParams)[0]}"); + + await Guard(() => ForEachMinerAsync(async (connection, ct) => + { + var context = connection.ContextAs(); + var minerJobParams = CreateWorkerJob(connection, (bool) ((object[]) jobParams)[^1]); + + // varDiff: if the client has a pending difficulty change, apply it now + if(context.ApplyPendingDifficulty()) + await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + + // send job + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); + })); + } + + public override double HashrateFromShares(double shares, double interval) + { + var result = shares / interval; + + return result; + } + + public override double ShareMultiplier => 1; + + #region Overrides + + public override void Configure(PoolConfig pc, ClusterConfig cc) + { + coin = pc.Template.As(); + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); + + base.Configure(pc, cc); + } + + protected override async Task SetupJobManager(CancellationToken ct) + { + var extraNonce1Size = extraPoolConfig?.ExtraNonce1Size ?? 4; + + manager = ctx.Resolve( + new TypedParameter(typeof(IExtraNonceProvider), new WarthogExtraNonceProvider(poolConfig.Id, extraNonce1Size, clusterConfig.InstanceId))); + + manager.Configure(poolConfig, clusterConfig); + + await manager.StartAsync(ct); + + if(poolConfig.EnableInternalStratum == true) + { + disposables.Add(manager.Jobs + .Select(job => Observable.FromAsync(() => + Guard(()=> OnNewJobAsync(job), + ex=> logger.Debug(() => $"{nameof(OnNewJobAsync)}: {ex.Message}")))) + .Concat() + .Subscribe(_ => { }, ex => + { + logger.Debug(ex, nameof(OnNewJobAsync)); + })); + + // start with initial blocktemplate + await manager.Jobs.Take(1).ToTask(ct); + } + + else + { + // keep updating NetworkStats + disposables.Add(manager.Jobs.Subscribe()); + } + } + + protected override async Task InitStatsAsync(CancellationToken ct) + { + await base.InitStatsAsync(ct); + + blockchainStats = manager.BlockchainStats; + } + + protected override WorkerContextBase CreateWorkerContext() + { + return new WarthogWorkerContext(); + } + + protected override async Task OnRequestAsync(StratumConnection connection, + Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + + try + { + switch(request.Method) + { + case BitcoinStratumMethods.Authorize: + await OnAuthorizeAsync(connection, tsRequest, ct); + break; + + case BitcoinStratumMethods.Subscribe: + await OnSubscribeAsync(connection, tsRequest); + break; + + case BitcoinStratumMethods.SubmitShare: + await OnSubmitAsync(connection, tsRequest, ct); + break; + + default: + logger.Debug(() => $"[{connection.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); + + await connection.RespondErrorAsync(StratumError.Other, $"Unsupported request {request.Method}", request.Id); + break; + } + } + + catch(StratumException ex) + { + await connection.RespondErrorAsync(ex.Code, ex.Message, request.Id, false); + } + } + + protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, double newDiff, CancellationToken ct) + { + await base.OnVarDiffUpdateAsync(connection, newDiff, ct); + + if(connection.Context.ApplyPendingDifficulty()) + { + var minerJobParams = CreateWorkerJob(connection, (bool) ((object[]) currentJobParams)[^1]); + + await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { connection.Context.Difficulty }); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, minerJobParams); + } + } + + #endregion // Overrides +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Warthog/WarthogUtils.cs b/src/Miningcore/Blockchain/Warthog/WarthogUtils.cs new file mode 100644 index 0000000000..b5c53bc477 --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/WarthogUtils.cs @@ -0,0 +1,1095 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Numerics; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Text; +using Miningcore.Extensions; +using Miningcore.Util; + +#pragma warning disable 3021 // disable CLSCompliant attribute warnings - http://msdn.microsoft.com/en-us/library/1x9049cy(v=vs.90).aspx + +namespace Miningcore.Blockchain.Warthog; + +public static class WarthogUtils +{ + // Bit-mask used for extracting the exponent bits of a Double (0x7ff0000000000000). + public const long DBL_EXP_MASK = 0x7ff0000000000000L; + + // The number of bits in the mantissa of a Double, excludes the implicit leading 1 bit (52). + public const int DBL_MANT_BITS = 52; + + // Bit-mask used for extracting the sign bit of a Double (0x8000000000000000). + public const long DBL_SGN_MASK = -1 - 0x7fffffffffffffffL; + + // Bit-mask used for extracting the mantissa bits of a Double (0x000fffffffffffff). + public const long DBL_MANT_MASK = 0x000fffffffffffffL; + + // Bit-mask used for clearing the exponent bits of a Double (0x800fffffffffffff). + public const long DBL_EXP_CLR_MASK = DBL_SGN_MASK | DBL_MANT_MASK; + + public static double CalculateHashrate(WarthogCustomFloat sha256t, WarthogCustomFloat verus) + { + double hashrate = (10.0 / 3.0) * (double)sha256t * (Math.Pow(((double)WarthogConstants.ProofOfBalancedWorkC + (double)verus / (double)sha256t), 3.0) - Math.Pow((double)WarthogConstants.ProofOfBalancedWorkC, 3.0)); + + return hashrate; + } + + /* public static void Frexp(double value, out double significand, out int exponent) + { + // Special case for zero + if(value == 0.0) + { + significand = 0.0; + exponent = 0; + return; + } + + // Get the raw bits of the double + long bits = BitConverter.DoubleToInt64Bits(value); + + bool negative = (bits >> 63) != 0; + + // Extract the exponent (bits 52-62) + int rawExponent = (int)((bits >> 52) & 0x7FFL); + + // Extract the mantissa (bits 0-51) + long mantissa = bits & 0xFFFFFFFFFFFFFL; + + // If the exponent is zero, this is a subnormal number + if(rawExponent == 0) + rawExponent++; + // Add the implicit leading 1 bit to the mantissa + else + mantissa = mantissa | (1L << 52); + + // Adjust the exponent from the biased representation + exponent = rawExponent - 1023; + + // Calculate the significand + significand = mantissa / Math.Pow(2.0, 52); + + // Adjust the sign if necessary + if(negative) + significand = -significand; + }*/ + + public static void Frexp(double value, out double significand, out int exponent) + { + significand = value; + long bits = BitConverter.DoubleToInt64Bits(significand); + int exp = (int)((bits & DBL_EXP_MASK) >> DBL_MANT_BITS); + exponent = 0; + + if (exp == 0x7ff || significand == 0D) + significand += significand; + else + { + // Not zero and finite. + exponent = exp - 1022; + if (exp == 0) + { + // Subnormal, scale significand so that it is in [1, 2). + significand *= BitConverter.Int64BitsToDouble(0x4350000000000000L); // 2^54 + bits = BitConverter.DoubleToInt64Bits(significand); + exp = (int)((bits & DBL_EXP_MASK) >> DBL_MANT_BITS); + exponent = exp - 1022 - 54; + } + // Set exponent to -1 so that significand is in [0.5, 1). + significand = BitConverter.Int64BitsToDouble((bits & DBL_EXP_CLR_MASK) | 0x3fe0000000000000L); + } + } +} + +public class WarthogExponential +{ + public uint negExp { get; private set; } = 0; // negative exponent of 2 + public uint data { get; private set; } = 0x80000000; + + public WarthogExponential() { } + + public WarthogExponential(ReadOnlySpan hash) + { + negExp += 1; // we are considering hashes as number in (0,1), padded with infinite amount of trailing 1's + int i = 0; + for(; i < hash.Length; ++i) + { + if(hash[i] != 0) + break; + negExp += 8; + } + + ulong tmpData = 0; + for(int j = 0; ; ++j) + { + if(i < hash.Length) + tmpData |= hash[i++]; + else + tmpData |= 0xFFu; // "infinite amount of trailing 1's" + + if(j >= 3) + break; + tmpData <<= 8; + } + + while((tmpData & 0x80000000ul) == 0) + { + negExp += 1; + tmpData <<= 1; + } + + tmpData *= (ulong)data; + if(tmpData >= (ulong)(1ul << 63)) + { + tmpData >>= 1; + negExp -= 1; + } + + tmpData >>= 31; + + data = (uint)tmpData; + } +} + +public class WarthogTarget +{ + public bool IsJanusHash { get; private set; } = true; + public uint data { get; private set; } = 0u; + + public WarthogTarget(uint data, bool isJanusHash = true) + { + this.data = data; + this.IsJanusHash = isJanusHash; + } + + public WarthogTarget(byte[] data, bool isJanusHash = true) + { + this.data = uint.Parse(data.ToHexString(), NumberStyles.HexNumber); + this.IsJanusHash = isJanusHash; + } + + public WarthogTarget(double difficulty, bool isJanusHash = true) + { + if(difficulty < 1.0) + difficulty = 1.0; + + this.IsJanusHash = isJanusHash; + + WarthogUtils.Frexp(difficulty, out var coef, out var exp); + double inv = 1 / coef; + uint zeros; + uint digits; + + if(!this.IsJanusHash) + { + if(exp - 1 >= 256 - 24) + { + data = WarthogConstants.HardestTargetHost; + return; + } + + zeros = (uint)(exp - 1); + if(inv == 2.0) + { + Set(zeros, 0x00FFFFFF); + } + else + { + digits = (uint)Math.Floor(Math.ScaleB(inv, 23)); + if(digits < 0x00800000) + Set(zeros, 0x00800000); + else if(digits > 0x00FFFFFF) + Set(zeros, 0x00FFFFFF); + else + Set(zeros, digits); + } + } + else + { + zeros = (uint)(exp - 1); + if(zeros >= 3 * 256) + { + data = WarthogConstants.JanusHashMaxTargetHost; + return; + } + if(inv == 2.0) + { + Set(zeros, 0x003fffff); + } + else + { + digits = (uint)Math.Floor(Math.ScaleB(inv, 21)); + if(digits < 0x00200000) + Set(zeros, 0x00200000); + else if(digits > 0x003fffff) + Set(zeros, 0x003fffff); + else + Set(zeros, digits); + } + } + } + + private void Set(uint zeros, uint bytes) + { + data = (!this.IsJanusHash) ? (zeros << 24) | bytes : (zeros << 22) | bytes; + } + + public uint Zeros8() + { + return data >> 24; + } + + public uint Zeros10() + { + return data >> 22; + } + + public uint Bits22() + { + return data & 0x003FFFFF; + } + + public uint Bits24() + { + return data & 0x00FFFFFF; + } + + public double Difficulty() + { + int zeros; + double dbits; + + if(!IsJanusHash) + { + zeros = (int)Zeros8(); + dbits = Bits24(); + return Math.Pow(2, zeros + 24) / dbits; + } + else + { + zeros = (int)Zeros10(); + dbits = Bits22(); + return Math.Pow(2, zeros + 22) / dbits; + } + } + + public static bool operator <(WarthogCustomFloat wcf, WarthogTarget wt) + { + if(!wt.IsJanusHash) + return false; + else + { + uint zerosTarget = wt.Zeros10(); + int exp = wcf._exponent; + if(exp < 0) + exp = -exp; + uint zerosHashProduct = (uint)exp; + + if(zerosTarget > zerosHashProduct) + return false; + + if(zerosTarget < zerosHashProduct) + return true; + + ulong bits32 = wt.Bits22() << 10; + return wcf._mantissa < bits32; + } + } + + public static bool operator >(WarthogCustomFloat wcf, WarthogTarget wt) + { + if(!wt.IsJanusHash) + return false; + else + { + uint zerosTarget = wt.Zeros10(); + int exp = wcf._exponent; + if(exp < 0) + exp = -exp; + uint zerosHashProduct = (uint)exp; + + if(zerosTarget > zerosHashProduct) + return true; + + if(zerosTarget < zerosHashProduct) + return false; + + ulong bits32 = wt.Bits22() << 10; + return wcf._mantissa > bits32; + } + } + + public static bool operator <(ReadOnlySpan hash, WarthogTarget wt) + { + if(!wt.IsJanusHash) + { + uint zeros = wt.Zeros8(); + if(zeros > (256 - 4 * 8)) + return false; + uint bits = wt.Bits24(); + if((bits & 0x00800000) == 0) + return false; // first digit must be 1 + int zeroBytes = (int)(zeros / 8); // number of complete zero bytes + int shift = (int)(zeros & 0x07); + + for(int i = 0; i < zeroBytes; ++i) + if(hash[31 - i] != 0) + return false; // here we need zeros + + uint threshold = bits << (8 - shift); + byte[] dst = hash.ToArray().Skip(28 - zeroBytes).Take(4).ToArray(); + uint candidate = uint.Parse(dst.ToHexString(), NumberStyles.HexNumber); + if(candidate > threshold) + { + return false; + } + if(candidate < threshold) + { + return true; + } + for(int i = 0; i < 28 - zeroBytes; ++i) + if(hash[i] != 0) + return false; + return true; + } + else + { + WarthogExponential we = new WarthogExponential(hash); + uint zerosTarget = wt.Zeros10(); + uint zerosHashProduct = (uint)(we.negExp - 1); + + if(zerosTarget > zerosHashProduct) + return false; + + if(zerosTarget < zerosHashProduct) + return true; + + uint bits32 = wt.Bits22() << 10; + return we.data < bits32; + } + } + + public static bool operator >(ReadOnlySpan hash, WarthogTarget wt) + { + if(!wt.IsJanusHash) + { + uint zeros = wt.Zeros8(); + if(zeros < (256 - 4 * 8)) + return false; + uint bits = wt.Bits24(); + if((bits & 0x00800000) != 0) + return false; // first digit must be 1 + int zeroBytes = (int)(zeros / 8); // number of complete zero bytes + int shift = (int)(zeros & 0x07); + + for(int i = 0; i < zeroBytes; ++i) + if(hash[31 - i] == 0) + return false; // here we need zeros + + uint threshold = bits << (8 - shift); + byte[] dst = hash.ToArray().Skip(28 - zeroBytes).Take(4).ToArray(); + uint candidate = uint.Parse(dst.ToHexString(), NumberStyles.HexNumber); + if(candidate < threshold) + { + return false; + } + if(candidate > threshold) + { + return true; + } + for(int i = 0; i < 28 - zeroBytes; ++i) + if(hash[i] == 0) + return false; + return true; + } + else + { + WarthogExponential we = new WarthogExponential(hash); + uint zerosTarget = wt.Zeros10(); + uint zerosHashProduct = (uint)(we.negExp - 1); + + if(zerosTarget > zerosHashProduct) + return true; + + if(zerosTarget < zerosHashProduct) + return false; + + uint bits32 = wt.Bits22() << 10; + return we.data > bits32; + } + } +} + +// https://github.com/CoinFuMasterShifu/CustomFloat/blob/master/src/custom_float.hpp +[Serializable] +[ComVisible(false)] +public class WarthogCustomFloat : IComparable, IComparable, IDeserializationCallback, + IEquatable, + ISerializable +{ + // ---- SECTION: members supporting exposed properties -------------* + public int _exponent { get; private set; } = 0; + public uint _mantissa { get; private set; } = 0; + public bool _isPositive { get; private set; } = true; + + #region Public Properties + + public long Exponent + { + get => (long)this._exponent; + set + { + if(!(value < int.MaxValue && value > int.MinValue)) + throw new Exception($"Invalid value for Exponent: {value} < {int.MaxValue} && {value} > {int.MinValue}"); + + this._exponent = (int)value; + } + } + + public ulong Mantissa + { + get => (ulong)this._mantissa; + set + { + if(!(value < (ulong)(1ul << 32) && value != 0)) + throw new Exception($"Invalid value for Mantissa: {value} < {(ulong)(1ul << 32)} && {value} != 0"); + + this._mantissa = (uint)value; + } + } + + public bool IsPositive + { + get => this._isPositive; + set + { + this._isPositive = value; + } + } + + #endregion Public Properties + + // ---- SECTION: public instance methods --------------* + + #region Public Instance Methods + + private void SetAssert(long exponent, ulong mantissa) + { + this.Exponent = exponent; + + if(mantissa == 0) + this._mantissa = 0; + else + this.Mantissa = mantissa; + } + + public void ShiftLeft(long exponent, ulong mantissa) + { + while(mantissa < 0x80000000ul) + { + mantissa <<= 1; + exponent -= 1; + } + + this.SetAssert(exponent, mantissa); + } + + public void ShiftRight(long exponent, ulong mantissa) + { + while(mantissa >= (1ul << 32)) + { + mantissa >>= 1; + exponent += 1; + } + + this.SetAssert(exponent, mantissa); + } + + public override bool Equals(object obj) + { + return obj is WarthogCustomFloat customfloat && Equals(customfloat); + } + + public override int GetHashCode() + { + return ((double)this).GetHashCode(); + } + + // IComparable + int IComparable.CompareTo(object obj) + { + if(obj == null) + return 1; + if(obj is not WarthogCustomFloat customfloat) + throw new ArgumentException("Argument must be of type WarthogCustomFloat", "obj"); + return Compare(this, customfloat); + } + + // IComparable + public int CompareTo(WarthogCustomFloat other) + { + return Compare(this, other); + } + + // Object.ToString (x * 2^n) + public override string ToString() + { + double r = (double)this._mantissa / (ulong)(1ul << 32); + + if(!this._isPositive) + r = -r; + + var ret = new StringBuilder(); + ret.Append(r.ToString("F", CultureInfo.InvariantCulture)); + ret.Append(" * 2^"); + ret.Append(this._exponent.ToString("D", CultureInfo.InvariantCulture)); + return ret.ToString(); + } + + // IEquatable + // a/b = c/d, if ad = bc + public bool Equals(WarthogCustomFloat other) + { + if(this._exponent == other._exponent && this._mantissa == other._mantissa) + return this._isPositive == other._isPositive; + + long xMantissa = (long)this._mantissa; + if(!this._isPositive) + xMantissa = -xMantissa; + long yMantissa = other._mantissa; + if(!other._isPositive) + yMantissa = -yMantissa; + + return xMantissa * other._exponent == this._exponent * yMantissa; + } + + #endregion Public Instance Methods + + // -------- SECTION: constructors -----------------* + + #region Constructors + + public WarthogCustomFloat(int exponent, uint mantissa, bool isPositive) + { + this._exponent = exponent; + this._mantissa = mantissa; + this._isPositive = isPositive; + } + + public WarthogCustomFloat(ReadOnlySpan hash) + { + this._isPositive = true; + int exponent = 0; + int i = 0; + for(; i < hash.Length; ++i) + { + if(hash[i] != 0) + break; + exponent -= 8; + } + + ulong tmpData = 0; + + for(int j = 0; ; ++j) + { + if(i < hash.Length) + tmpData |= hash[i++]; + else + tmpData |= 0xFFu; // "infinite amount of trailing 1's" + + if(j >= 3) + break; + + tmpData <<= 8; + } + + ShiftLeft(exponent, tmpData); + } + + public WarthogCustomFloat(double d) + { + if(d == 0) + { + this._exponent = 0; + this._mantissa = 0; + this._isPositive = true; + } + else + { + WarthogUtils.Frexp(d, out var r, out var e); + + bool isPositive = r >= 0; + if(r < 0) + r = -r; + + r *= (ulong)(1ul << 32); + ulong m = (ulong)Math.Ceiling(r); + + this._exponent = e; + this.Mantissa = m; + this._isPositive = isPositive; + } + } + + public WarthogCustomFloat(int mantissa) + { + if(mantissa == 0) + { + this._exponent = 0; + this._mantissa = 0; + this._isPositive = true; + } + else + { + this.IsPositive = mantissa >= 0; + + if(mantissa < 0) + mantissa = -mantissa; + + ulong tmpData = (ulong)mantissa; + + ShiftLeft(32, tmpData); + } + } + + public WarthogCustomFloat(long exponent, bool isPositive) + { + if(exponent >= int.MaxValue || exponent <= int.MinValue) + throw new ArgumentException($"Invalid value for exponent: {exponent} < {int.MaxValue} && {exponent} > {int.MinValue}"); + + this.Exponent = exponent + 1; + this.Mantissa = 0x80000000ul; + this.IsPositive = isPositive; + } + + #endregion Constructors + + // -------- SECTION: public static methods -----------------* + + #region Public Static Methods + + public static WarthogCustomFloat Negate(WarthogCustomFloat wcf) + { + return new(wcf._exponent, wcf._mantissa, !wcf._isPositive); + } + + public static WarthogCustomFloat Add(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + return wcf1 + wcf2; + } + + public static WarthogCustomFloat Subtract(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + return wcf1 - wcf2; + } + + public static WarthogCustomFloat Multiply(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + return wcf1 * wcf2; + } + + public static WarthogCustomFloat Divide(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + return wcf1 / wcf2; + } + + public static WarthogCustomFloat Pow(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + return Pow2(wcf2 * Log2(wcf1)); + } + + public static WarthogCustomFloat Zero() + { + return new(0, 0, true); + } + + public static WarthogCustomFloat One() + { + return new(0, 1, true); + } + + public static int Compare(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + return ((double)wcf1).CompareTo((double)wcf2); + } + + #endregion Public Static Methods + + #region Operator Overloads + + public static bool operator ==(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + return wcf1.Equals(wcf2); + } + + public static bool operator !=(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + return !wcf1.Equals(wcf2); + } + + public static bool operator <(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + int expWcf2 = wcf2._exponent; + if(expWcf2 < 0) + expWcf2 = -expWcf2; + uint zerosWcf2 = (uint)expWcf2; + + int expWcf1 = wcf1._exponent; + if(expWcf1 < 0) + expWcf1 = -expWcf1; + uint zerosWcf1 = (uint)expWcf1; + + if(zerosWcf1 < zerosWcf2) + return false; + + if(zerosWcf1 > zerosWcf2) + return true; + + return wcf1._mantissa < wcf2._mantissa; + } + + public static bool operator <=(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + int expWcf2 = wcf2._exponent; + if(expWcf2 < 0) + expWcf2 = -expWcf2; + uint zerosWcf2 = (uint)expWcf2; + + int expWcf1 = wcf1._exponent; + if(expWcf1 < 0) + expWcf1 = -expWcf1; + uint zerosWcf1 = (uint)expWcf1; + + if(zerosWcf1 < zerosWcf2) + return false; + + if(zerosWcf1 >= zerosWcf2) + return true; + + return wcf1._mantissa <= wcf2._mantissa; + } + + public static bool operator >(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + return !(wcf1 < wcf2); + } + + public static bool operator >=(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + return !(wcf1 <= wcf2); + } + + public static WarthogCustomFloat operator +(WarthogCustomFloat wcf) + { + return wcf; + } + + public static WarthogCustomFloat operator -(WarthogCustomFloat wcf) + { + return new(wcf._exponent, wcf._mantissa, !wcf._isPositive); + } + + public static WarthogCustomFloat operator ++(WarthogCustomFloat wcf) + { + return wcf + One(); + } + + public static WarthogCustomFloat operator --(WarthogCustomFloat wcf) + { + return wcf - One(); + } + + public static WarthogCustomFloat operator +(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + WarthogCustomFloat wcf3 = new(wcf1._exponent, wcf1._mantissa, wcf1._isPositive); + int e1 = wcf1._exponent; + int e2 = wcf2._exponent; + + if(wcf1._mantissa == 0) + { + wcf3._exponent = wcf2._exponent; + wcf3._mantissa = wcf2._mantissa; + wcf3._isPositive = wcf2._isPositive; + + return wcf3; + } + + if(wcf2._mantissa == 0) + return wcf3; + + if(e1 < e2) + return wcf2 + wcf1; + + if(e1 - e2 >= 64) + return wcf3; + + ulong tmp = wcf1._mantissa; + ulong operand = (ulong)wcf2._mantissa >> (e1 - e2); + + if(wcf1._isPositive == wcf2._isPositive) + { + tmp += operand; + + wcf3.ShiftRight(e1, tmp); + } + else + { + if(operand == tmp) + wcf3._mantissa = 0; + else if(operand > tmp) + { + wcf3._isPositive = wcf2._isPositive; // change sign + wcf3.ShiftLeft(e2, operand - tmp); + } + else + wcf3.ShiftLeft(e1, tmp - operand); + } + + return wcf3; + } + + public static WarthogCustomFloat operator -(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + WarthogCustomFloat wcf3 = new(wcf2._exponent, wcf2._mantissa, !wcf2._isPositive); + + return wcf1 + wcf3; + } + + public static WarthogCustomFloat operator *(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + WarthogCustomFloat wcf3 = new(wcf1._exponent, wcf1._mantissa, wcf1._isPositive); + if(wcf1._mantissa == 0 || wcf2._mantissa == 0) + { + wcf3._mantissa = 0; + return wcf3; + } + + wcf3.IsPositive = wcf1._isPositive == wcf2._isPositive; + int e1 = wcf1._exponent; + int e2 = wcf2._exponent; + long e = (long)(e1 + e2); + ulong tmp = (ulong)wcf1._mantissa * wcf2._mantissa; + + if(tmp < (1ul << 63)) + { + e -= 1; + tmp <<= 1; + } + + tmp >>= 32; + wcf3.SetAssert(e, tmp); + + return wcf3; + } + + public static WarthogCustomFloat operator /(WarthogCustomFloat wcf1, WarthogCustomFloat wcf2) + { + WarthogCustomFloat wcf3 = new(wcf1._exponent, wcf1._mantissa, wcf1._isPositive); + if (wcf2._mantissa == 0) + throw new DivideByZeroException("Attempt to divide by zero."); + + if (wcf1._mantissa == 0) + { + wcf3._mantissa = 0; + return wcf3; + } + + wcf3.IsPositive = wcf1._isPositive == wcf2._isPositive; + int e1 = wcf1._exponent; + int e2 = wcf2._exponent; + long e = (long)(e1 - e2); + + ulong dividend = (ulong)wcf1._mantissa; + ulong divisor = (ulong)wcf2._mantissa; + + ulong tmp = (ulong)Math.Ceiling((double)(dividend / divisor)); + + wcf3.SetAssert(e, tmp); + + return wcf3; + } + + #endregion Operator Overloads + + // ----- SECTION: explicit conversions from WarthogCustomFloat to numeric base types ----------------* + + #region explicit conversions from WarthogCustomFloat + + public static explicit operator double(WarthogCustomFloat value) + { + if(value._mantissa == 0) + return 0; + + double r = (double)value._mantissa / (ulong)(1ul << 32); + + if(!value._isPositive) + r = -r; + + // return Math.Pow(2, value._exponent) * r; + return Math.ScaleB(r, value._exponent); + } + + #endregion explicit conversions from WarthogCustomFloat + + // ----- SECTION: implicit conversions from numeric base types to WarthogCustomFloat ----------------* + + #region implicit conversions to WarthogCustomFloat + + #endregion implicit conversions to WarthogCustomFloat + + // ----- SECTION: private serialization instance methods ----------------* + + #region serialization + + void IDeserializationCallback.OnDeserialization(object sender) + { + try + { + // verify that the deserialized number is well formed + SetAssert(this._exponent, this._mantissa); + } + catch(ArgumentException e) + { + throw new SerializationException("invalid serialization data", e); + } + } + + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + if(info == null) + throw new ArgumentNullException(nameof(info)); + + info.AddValue("Exponent", this._exponent); + info.AddValue("Mantissa", this._mantissa); + info.AddValue("IsPositive", this._isPositive); + } + + private WarthogCustomFloat(SerializationInfo info, StreamingContext context) + { + if(info == null) + throw new ArgumentNullException(nameof(info)); + + this._exponent = (int) info.GetValue("Exponent", typeof(int)); + this._mantissa = (uint) info.GetValue("Mantissa", typeof(uint)); + this._isPositive = (bool) info.GetValue("IsPositive", typeof(bool)); + } + + #endregion serialization + + // ----- SECTION: private instance utility methods ----------------* + + #region instance helper methods + + #endregion instance helper methods + + // ----- SECTION: private static utility methods -----------------* + + #region static helper methods + + public static WarthogCustomFloat Pow2(WarthogCustomFloat wcf) + { + WarthogCustomFloat wcf1; + + if(wcf._mantissa == 0) + { + wcf1 = new(1); + return wcf1; + } + + int e_x = wcf._exponent; + uint m = wcf._mantissa; + + if(e_x == 32) + { + if(wcf._isPositive) + { + wcf1 = new((long)m, true); + return wcf1; + } + + wcf1 = new(-((long)m), true); + return wcf1; + } + else + { + if(e_x > 0) + { + long e = (long)(m >> (32 - e_x)); + uint m_frac = (uint)(m << e_x); + if(m_frac == 0) + { + if(wcf._isPositive) + { + wcf1 = new(e, true); + return wcf1; + } + + wcf1 = new(e, true); + wcf1.Exponent = -wcf1.Exponent; + wcf1.Exponent += 2; + + return wcf1; + } + + WarthogCustomFloat frac = Zero(); + frac.ShiftLeft(0, m_frac); + + if(wcf._isPositive) + { + wcf1 = Pow2Fraction(frac); + wcf1.Exponent += e; + + return wcf1; + } + + wcf1 = Pow2Fraction(new WarthogCustomFloat(1) - frac); + wcf1.Exponent += e - 1; + wcf1.Exponent = -wcf1.Exponent; + + return wcf1; + } + else + { + if(wcf._isPositive) + return Pow2Fraction(wcf); + + wcf1 = Pow2Fraction(new WarthogCustomFloat(1) + wcf); + wcf1.Exponent = -wcf1.Exponent; + wcf1.Exponent += 1; + + return wcf1; + } + } + } + + public static WarthogCustomFloat Log2(WarthogCustomFloat wcf) + { + WarthogCustomFloat wcf1 = new(wcf._exponent, wcf._mantissa, wcf._isPositive); + int e = wcf._exponent; + wcf1._exponent = 0; + WarthogCustomFloat c0 = new(1, 2872373668, true); // = 1.33755322 + WarthogCustomFloat c1 = new(3, 2377545675, false); // = -4.42852392 + WarthogCustomFloat c2 = new(3, 3384280813, true); // = 6.30371424 + WarthogCustomFloat c3 = new(2, 3451338727, false); // = -3.21430967 + WarthogCustomFloat d = c3 + wcf1 * (c2 + wcf1 * (c1 + wcf1 * c0)); + + return new WarthogCustomFloat(e) + d; + } + + public static WarthogCustomFloat Pow2Fraction(WarthogCustomFloat wcf) + { + WarthogCustomFloat wcf1 = new(wcf._exponent, wcf._mantissa, wcf._isPositive); + // I have modified constants from here: https://github.com/nadavrot/fast_log/blob/83bd112c330976c291300eaa214e668f809367ab/src/exp_approx.cc#L18 + // such that they don't compute the euler logartihm but logarithm to base 2. + WarthogCustomFloat c0 = new(-3, 3207796260, true); // = 0.09335915850659268 + WarthogCustomFloat c1 = new(-2, 3510493713, true); // = 0.2043376277254389 + WarthogCustomFloat c2 = new(0, 3014961390, true); // = 0.7019754011048444 + WarthogCustomFloat c3 = new(1, 2147933481, true); // = 1.00020947 + WarthogCustomFloat d = c3 + wcf1 * (c2 + wcf1 * (c1 + wcf1 * c0)); + + return d; + } + + #endregion static helper methods +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Warthog/WarthogWorkerContext.cs b/src/Miningcore/Blockchain/Warthog/WarthogWorkerContext.cs new file mode 100644 index 0000000000..cb655c384d --- /dev/null +++ b/src/Miningcore/Blockchain/Warthog/WarthogWorkerContext.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; +using Miningcore.Mining; + +namespace Miningcore.Blockchain.Warthog; + +public class WarthogWorkerContext : WorkerContextBase +{ + /// + /// Usually a wallet address + /// + public override string Miner { get; set; } + + /// + /// Arbitrary worker identififer for miners using multiple rigs + /// + public override string Worker { get; set; } + + /// + /// Unique value assigned per worker + /// + public string ExtraNonce1 { get; set; } + + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); + + public virtual void AddJob(WarthogJob job, int maxActiveJobs) + { + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); + + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); + } + + public WarthogJob GetJob(string jobId) + { + return validJobs.ToArray().FirstOrDefault(x => x.JobId == jobId); + } +} diff --git a/src/Miningcore/Blockchain/Xelis/Configuration/XelisDaemonEndpointConfigExtra.cs b/src/Miningcore/Blockchain/Xelis/Configuration/XelisDaemonEndpointConfigExtra.cs new file mode 100644 index 0000000000..74ab2786f0 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/Configuration/XelisDaemonEndpointConfigExtra.cs @@ -0,0 +1,19 @@ +namespace Miningcore.Blockchain.Xelis.Configuration; + +public class XelisDaemonEndpointConfigExtra +{ + /// + /// Optional port for streaming WebSocket data + /// + public int? PortWs { get; set; } + + /// + /// Optional http-path for streaming WebSocket data + /// + public string HttpPathWs { get; set; } + + /// + /// Optional: Use SSL to for daemon websocket streaming + /// + public bool SslWs { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/Configuration/XelisPaymentProcessingConfigExtra.cs b/src/Miningcore/Blockchain/Xelis/Configuration/XelisPaymentProcessingConfigExtra.cs new file mode 100644 index 0000000000..86d4f3e37a --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/Configuration/XelisPaymentProcessingConfigExtra.cs @@ -0,0 +1,22 @@ +namespace Miningcore.Blockchain.Xelis.Configuration; + +public class XelisPaymentProcessingConfigExtra +{ + /// + /// Minimum block confirmations + /// Default: "Mainnet" (60) - "Testnet" (50) + /// + public int? MinimumConfirmations { get; set; } + + /// + /// Maximum of simultaneous destination address in a single transaction + /// Default: 255 + /// + public int? MaximumDestinationPerTransfer { get; set; } + + /// + /// If True, miners pay payment tx fees + /// Default: False + /// + public bool KeepTransactionFees { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Xelis/Configuration/XelisPoolConfigExtra.cs b/src/Miningcore/Blockchain/Xelis/Configuration/XelisPoolConfigExtra.cs new file mode 100644 index 0000000000..7d37fd804a --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/Configuration/XelisPoolConfigExtra.cs @@ -0,0 +1,14 @@ +using Miningcore.Configuration; + +namespace Miningcore.Blockchain.Xelis.Configuration; + +public class XelisPoolConfigExtra +{ + /// + /// Maximum number of tracked jobs. + /// Default: 8 + /// + public int? MaxActiveJobs { get; set; } + + public int? ExtraNonce1Size { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Xelis/DaemonRequests/BuildTransactionRequest.cs b/src/Miningcore/Blockchain/Xelis/DaemonRequests/BuildTransactionRequest.cs new file mode 100644 index 0000000000..459eb8c31d --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonRequests/BuildTransactionRequest.cs @@ -0,0 +1,43 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonRequests; + +public class BuildTransactionTransfer +{ + public ulong Amount { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string Asset { get; set; } + + public string Destination { get; set; } + + [JsonProperty("extra_data", NullValueHandling = NullValueHandling.Ignore)] + public string ExtraData { get; set; } +} + +public class BuildTransactionFee +{ + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public double? Multiplier { get; set; } + + [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] + public ulong? Amount { get; set; } +} + +public class BuildTransactionRequest +{ + public BuildTransactionTransfer[] Transfers { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public BuildTransactionFee Fee { get; set; } + + public bool broadcast { get; set; } = true; + + [JsonProperty("tx_as_hex")] + public bool TransactionAsHexadecimal { get; set; } = true; +} + +public class EstimateFeesRequest +{ + public BuildTransactionTransfer[] Transfers { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonRequests/ExtractKeyFromAddressRequest.cs b/src/Miningcore/Blockchain/Xelis/DaemonRequests/ExtractKeyFromAddressRequest.cs new file mode 100644 index 0000000000..2a58dacd2c --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonRequests/ExtractKeyFromAddressRequest.cs @@ -0,0 +1,11 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonRequests; + +public class ExtractKeyFromAddressRequest +{ + public string Address { get; set; } + + [JsonProperty("as_hex")] + public bool AsHexadecimal { get; set; } = true; +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonRequests/GetBlockByHashRequest.cs b/src/Miningcore/Blockchain/Xelis/DaemonRequests/GetBlockByHashRequest.cs new file mode 100644 index 0000000000..441434660f --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonRequests/GetBlockByHashRequest.cs @@ -0,0 +1,11 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonRequests; + +public class GetBlockByHashRequest +{ + public string Hash { get; set; } + + [JsonProperty("include_txs")] + public bool IncludeTransactions { get; set; } = true; +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonRequests/GetBlockHeaderRequest.cs b/src/Miningcore/Blockchain/Xelis/DaemonRequests/GetBlockHeaderRequest.cs new file mode 100644 index 0000000000..ee3371e20e --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonRequests/GetBlockHeaderRequest.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Xelis.DaemonRequests; + +public class GetBlockHeaderRequest +{ + public string Address { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonRequests/GetBlockTemplateRequest.cs b/src/Miningcore/Blockchain/Xelis/DaemonRequests/GetBlockTemplateRequest.cs new file mode 100644 index 0000000000..58433b48aa --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonRequests/GetBlockTemplateRequest.cs @@ -0,0 +1,11 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonRequests; + +public class GetBlockTemplateRequest +{ + [JsonProperty("template")] + public string BlockHeader { get; set; } + + public string Address { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonRequests/SetOnlineModeRequest.cs b/src/Miningcore/Blockchain/Xelis/DaemonRequests/SetOnlineModeRequest.cs new file mode 100644 index 0000000000..8275a931ec --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonRequests/SetOnlineModeRequest.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonRequests; + +public class SetOnlineModeRequest +{ + [JsonProperty("daemon_address")] + public string DaemonAddress { get; set; } + + [JsonProperty("auto_reconnect")] + public bool AutoReconnect { get; set; } = true; +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonRequests/SplitAddressRequest.cs b/src/Miningcore/Blockchain/Xelis/DaemonRequests/SplitAddressRequest.cs new file mode 100644 index 0000000000..d0ac766628 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonRequests/SplitAddressRequest.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Xelis.DaemonRequests; + +public class SplitAddressRequest +{ + public string Address { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonRequests/SubmitBlockRequest.cs b/src/Miningcore/Blockchain/Xelis/DaemonRequests/SubmitBlockRequest.cs new file mode 100644 index 0000000000..36e57302a0 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonRequests/SubmitBlockRequest.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonRequests; + +public class SubmitBlockRequest +{ + [JsonProperty("block_template")] + public string BlockTemplate { get; set; } + + [JsonProperty("miner_work", NullValueHandling = NullValueHandling.Ignore)] + public string MinerWork { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonRequests/SubscribeRequest.cs b/src/Miningcore/Blockchain/Xelis/DaemonRequests/SubscribeRequest.cs new file mode 100644 index 0000000000..8647bf5466 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonRequests/SubscribeRequest.cs @@ -0,0 +1,8 @@ +using Newtonsoft.Json; +namespace Miningcore.Blockchain.Xelis.DaemonRequests; + +public class SubscribeRequest +{ + [JsonProperty("notify")] + public string Notify { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonRequests/ValidateAddressRequest.cs b/src/Miningcore/Blockchain/Xelis/DaemonRequests/ValidateAddressRequest.cs new file mode 100644 index 0000000000..2d59119d64 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonRequests/ValidateAddressRequest.cs @@ -0,0 +1,11 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonRequests; + +public class ValidateAddressRequest +{ + public string Address { get; set; } + + [JsonProperty("allow_integrated")] + public bool AllowIntegrated { get; set; } = true; +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonResponses/BuildTransactionResponse.cs b/src/Miningcore/Blockchain/Xelis/DaemonResponses/BuildTransactionResponse.cs new file mode 100644 index 0000000000..bb0e734fcd --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonResponses/BuildTransactionResponse.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonResponses; + +public class BuildTransactionResponse +{ + public string Hash { get; set; } + public ulong Fee { get; set; } + + [JsonProperty("tx_as_hex")] + public string TxHash { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonResponses/ExtractKeyFromAddressResponse.cs b/src/Miningcore/Blockchain/Xelis/DaemonResponses/ExtractKeyFromAddressResponse.cs new file mode 100644 index 0000000000..703c7b341a --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonResponses/ExtractKeyFromAddressResponse.cs @@ -0,0 +1,9 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonResponses; + +public class ExtractKeyFromAddressResponse +{ + [JsonProperty("hex")] + public string PublicKey { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetBlockByHashResponse.cs b/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetBlockByHashResponse.cs new file mode 100644 index 0000000000..d98edd0706 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetBlockByHashResponse.cs @@ -0,0 +1,38 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonResponses; + +public class GetBlockByHashResponse +{ + [JsonProperty("block_type")] + public string BlockType { get; set; } + + [JsonProperty("cumulative_difficulty")] + public double CumulativeDifficulty { get; set; } + + [JsonProperty("dev_reward")] + public ulong DevReward { get; set; } + + public double Difficulty { get; set; } + + [JsonProperty("extra_nonce")] + public string ExtraNonce { get; set; } + + public string Hash { get; set; } + public ulong Height { get; set; } + public string Miner { get; set; } + + [JsonProperty("miner_reward")] + public ulong MinerReward { get; set; } + + public string Nonce { get; set; } + public ulong Reward { get; set; } + public ulong Supply { get; set; } + public ulong Timestamp { get; set; } + public ulong TopoHeight { get; set; } + + [JsonProperty("total_fees")] + public ulong TotalFees { get; set; } + + public byte Version { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetBlockHeaderResponse.cs b/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetBlockHeaderResponse.cs new file mode 100644 index 0000000000..ce385d669b --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetBlockHeaderResponse.cs @@ -0,0 +1,26 @@ +namespace Miningcore.Blockchain.Xelis.DaemonResponses; + +public class GetBlockHeaderResponse +{ + public string Algorithm { get; set; } + public double Difficulty { get; set; } + public ulong Height { get; set; } + + /* + * https://github.com/xelis-project/xelis-blockchain/blob/master/xelis_common/src/block/header.rs#L198 + * Block Header can be serialized/deserialized using following order on byte array: + * ------------------------------------------------------------ + * 1 byte for version + * 8 bytes for height (u64) big endian format + * 8 bytes for timestamp (u64) big endian format + * 8 bytes for nonce (u64) big endian format + * 32 bytes for extra nonce (this space is free and can be used to spread more the work or write anything) + * 1 byte for tips count + * 32 bytes per hash (count of elements is based on previous byte) + * 32 bytes for miner public key + * ------------------------------------------------------------ + */ + public string Template { get; set; } + + public ulong TopoHeight { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetBlockTemplateResponse.cs b/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetBlockTemplateResponse.cs new file mode 100644 index 0000000000..8053de3e97 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetBlockTemplateResponse.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonResponses; + +public class GetBlockTemplateResponse +{ + public string Algorithm { get; set; } + public double Difficulty { get; set; } + public ulong Height { get; set; } + + /* + * https://github.com/xelis-project/xelis-blockchain/blob/master/xelis_common/src/block/header.rs#L175 + * Block Template (Miner Work) can be serialized/deserialized using following order on byte array: + * ------------------------------------------------------------ + * 32 bytes for header work (immutable part in mining process) + * 8 bytes for timestamp (u64) big endian format (this space is free and can be used to spread more the work or write anything) + * 8 bytes for nonce (u64) big endian format (this space is free and can be used to spread more the work or write anything) + * 32 bytes for extra nonce (this space is free and can be used to spread more the work or write anything) + * 32 bytes for miner public key + * ------------------------------------------------------------ + */ + [JsonProperty("miner_work")] + public string Template { get; set; } + + public ulong TopoHeight { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetChainInfoResponse.cs b/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetChainInfoResponse.cs new file mode 100644 index 0000000000..576d06b64a --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetChainInfoResponse.cs @@ -0,0 +1,38 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonResponses; + +public class GetChainInfoResponse +{ + [JsonProperty("average_block_time")] + public ulong AverageBlockTime { get; set; } + + [JsonProperty("block_reward")] + public ulong BlockReward { get; set; } + + [JsonProperty("block_time_target")] + public ulong BlockTimeTarget { get; set; } + + [JsonProperty("circulating_supply")] + public ulong CirculatingSupply { get; set; } + + [JsonProperty("dev_reward")] + public ulong DevReward { get; set; } + + public ulong Height { get; set; } + + [JsonProperty("maximum_supply")] + public ulong MaximumSupply { get; set; } + + [JsonProperty("miner_reward")] + public ulong MinerReward { get; set; } + + public string Network { get; set; } + public ulong StableHeight { get; set; } + + [JsonProperty("top_block_hash")] + public string TopBlockHash { get; set; } + + public ulong TopoHeight { get; set; } + public string Version { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetDifficultyResponse.cs b/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetDifficultyResponse.cs new file mode 100644 index 0000000000..7b01d898cb --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetDifficultyResponse.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonResponses; + +public class GetDifficultyResponse +{ + public double Difficulty { get; set; } + public double Hashrate { get; set; } + + [JsonProperty("hashrate_formatted")] + public string HashrateFormatted { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetStatusResponse.cs b/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetStatusResponse.cs new file mode 100644 index 0000000000..2a425043d0 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonResponses/GetStatusResponse.cs @@ -0,0 +1,24 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonResponses; + +public class GetStatusResponse +{ + [JsonProperty("best_topoheight")] + public ulong BestTopoHeight { get; set; } + + [JsonProperty("max_peers")] + public uint MaxPeers { get; set; } + + [JsonProperty("median_topoheight")] + public ulong MedianTopoHeight { get; set; } + + [JsonProperty("our_topoheight")] + public ulong TopoHeight { get; set; } + + [JsonProperty("peer_count")] + public int PeerCount { get; set; } + + [JsonProperty("peer_id")] + public string PeerId { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/DaemonResponses/SplitAddressResponse.cs b/src/Miningcore/Blockchain/Xelis/DaemonResponses/SplitAddressResponse.cs new file mode 100644 index 0000000000..76ac094f25 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonResponses/SplitAddressResponse.cs @@ -0,0 +1,7 @@ +namespace Miningcore.Blockchain.Xelis.DaemonResponses; + +public class SplitAddressResponse +{ + public string Address { get; set; } +} + diff --git a/src/Miningcore/Blockchain/Xelis/DaemonResponses/ValidateAddressResponse.cs b/src/Miningcore/Blockchain/Xelis/DaemonResponses/ValidateAddressResponse.cs new file mode 100644 index 0000000000..01bf24fa10 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/DaemonResponses/ValidateAddressResponse.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Xelis.DaemonResponses; + +public class ValidateAddressResponse +{ + [JsonProperty("is_integrated")] + public bool IsIntegrated { get; set; } + + [JsonProperty("is_valid")] + public bool IsValid { get; set; } +} diff --git a/src/Miningcore/Blockchain/Xelis/XelisConstants.cs b/src/Miningcore/Blockchain/Xelis/XelisConstants.cs new file mode 100644 index 0000000000..bea4b79f68 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/XelisConstants.cs @@ -0,0 +1,88 @@ +using System; +using System.Globalization; +using System.Numerics; + +namespace Miningcore.Blockchain.Xelis; + +public static class XelisConstants +{ + public const int ExtranoncePlaceHolderLength = 32; + public static int NonceLength = 16; + + public const decimal SmallestUnit = 100000000; + public const string WalletDaemonCategory = "wallet"; + + public const string DaemonRpcLocation = "json_rpc"; + + public const int TargetPaddingLength = 32; + public static readonly double Pow2x32 = Math.Pow(2, 32); + public static BigInteger Diff1Target = BigInteger.Pow(2, 256) - 1; + + public const int BlockHeaderOffsetVersion = 0; + public const int BlockHeaderOffsetHeight = 1; + public const int BlockHeaderOffsetTimestamp = 9; + public const int BlockHeaderOffsetNonce = 17; + public const int BlockHeaderOffsetExtraNonce = 25; + public const int BlockHeaderOffsetTipsCount = 57; + public const int BlockHeaderOffsetTips = 58; + public const int BlockHeaderSizeTransactionsCount = 2; + public const int BlockHeaderSizeMinerPublicKey = 32; + + public const int BlockTemplateOffsetBlockHeaderWork = 0; + public const int BlockTemplateOffsetTimestamp = 32; + public const int BlockTemplateOffsetNonce = 40; + public const int BlockTemplateOffsetExtraNonce = 48; + public const int BlockTemplateOffsetMinerPublicKey = 80; + + public const int HashSize = 32; + public const int BlockWorkSize = 112; + + public const string AlgorithmXelisHashV2 = "xel/v2"; + + // Amount in ATOMIC (per KB) + public const decimal MinimumTransactionFees = 1000; + public const string TransactionDefaultAsset = "0000000000000000000000000000000000000000000000000000000000000000"; + public const int MaximumDestinationPerTransfer = 255; +} + +public static class XelisCommands +{ + public const string DaemonName = "xelis_daemon"; + + public const string GetChainInfo = "get_info"; + public const string GetBlockHeader = "get_block_template"; + public const string GetBlockTemplate = "get_miner_work"; + public const string GetBlockByHash = "get_block_by_hash"; + public const string GetDifficulty = "get_difficulty"; + public const string GetStatus = "p2p_status"; + + public const string ExtractKeyFromAddress = "extract_key_from_address"; + public const string ValidateAddress = "validate_address"; + public const string SplitAddress = "split_address"; + + public const string SubmitBlock = "submit_block"; + + public const string Subscribe = "subscribe"; + public const string NotifiyNewBlock = "new_block"; +} + +public static class XelisWalletCommands +{ + public const string DaemonName = "xelis_wallet"; + + public const string GetAddress = "get_address"; + public const string GetBalance = "get_balance"; + + public const string EstimateFees = "estimate_fees"; + public const string BuildTransaction = "build_transaction"; + + public const string IsOnline = "is_online"; + public const string SetOnlineMode = "set_online_mode"; +} + +public enum XelisRPCErrorCode +{ + // RPC_METHOD_NOT_FOUND is internally mapped to HTTP_NOT_FOUND (404). + // It should not be used for application-layer errors. + RPC_INVALID_PARAMS = -32602, +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Xelis/XelisExtraNonceProvider.cs b/src/Miningcore/Blockchain/Xelis/XelisExtraNonceProvider.cs new file mode 100644 index 0000000000..1d55032e13 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/XelisExtraNonceProvider.cs @@ -0,0 +1,8 @@ +namespace Miningcore.Blockchain.Xelis; + +public class XelisExtraNonceProvider : ExtraNonceProviderBase +{ + public XelisExtraNonceProvider(string poolId, int size, byte? clusterInstanceId) : base(poolId, size, clusterInstanceId) + { + } +} diff --git a/src/Miningcore/Blockchain/Xelis/XelisJob.cs b/src/Miningcore/Blockchain/Xelis/XelisJob.cs new file mode 100644 index 0000000000..9fc0d8daef --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/XelisJob.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections.Concurrent; +using System.Globalization; +using System.Linq; +using System.Numerics; +using System.Text; +using Miningcore.Blockchain.Xelis.DaemonResponses; +using Miningcore.Contracts; +using Miningcore.Crypto; +using Miningcore.Crypto.Hashing.Algorithms; +using Miningcore.Extensions; +using Miningcore.Native; +using Miningcore.Stratum; +using Miningcore.Time; +using Miningcore.Util; +using NBitcoin; + +namespace Miningcore.Blockchain.Xelis; + +public class XelisJob +{ + protected IMasterClock clock; + protected double shareMultiplier; + protected readonly IHashAlgorithm blake3Hasher = new Blake3(); + protected readonly IHashAlgorithm xelisHash = new XelisHash(); + protected readonly IHashAlgorithm xelisHashV2 = new XelisHashV2(); + + protected readonly ConcurrentDictionary submissions = new(StringComparer.OrdinalIgnoreCase); + public byte[] blockTargetBytes { get; protected set; } + public uint256 blockTargetValue { get; protected set; } + protected byte[] prevHashBytes; + protected byte[] versionBytes; + protected byte[] heightBytes; + protected byte[] nTimeBytes; + protected byte[] extraNonceBytes; + protected byte[] tipsCountBytes; + protected byte[] tipsBytes; + protected byte[] transactionsCountBytes; + protected byte[] transactionsBytes; + protected byte[] minerPublicKeyBytes; + + protected object[] jobParams; + + #region API-Surface + + public GetBlockHeaderResponse BlockHeader { get; protected set; } + public GetBlockTemplateResponse BlockTemplate { get; protected set; } + public string PrevHash { get; protected set; } + public double Difficulty { get; protected set; } + public string network { get; protected set; } + + public string JobId { get; protected set; } + + protected virtual byte[] SerializeCoinbase(byte[] extranonceBytes, byte[] nonceBytes) + { + using(var stream = new MemoryStream(XelisConstants.BlockWorkSize)) + { + var bw = new BinaryWriter(stream); + + bw.Write(prevHashBytes); + bw.Write(nTimeBytes); + bw.Write(nonceBytes); + bw.Write(extranonceBytes); + bw.Write(minerPublicKeyBytes); + + return stream.ToArray(); + } + } + + protected virtual byte[] SerializeHeader(byte[] extranonceBytes, byte[] nonceBytes) + { + using(var stream = new MemoryStream()) + { + var bw = new BinaryWriter(stream); + + bw.Write(versionBytes); + bw.Write(heightBytes); + bw.Write(nTimeBytes); + bw.Write(nonceBytes); + bw.Write(extranonceBytes); + bw.Write(tipsCountBytes); + + if(tipsBytes != null) + bw.Write(tipsBytes); + + bw.Write(transactionsCountBytes); + + if(transactionsBytes != null) + bw.Write(transactionsBytes); + + bw.Write(minerPublicKeyBytes); + + return stream.ToArray(); + } + } + + protected virtual Share ProcessShareInternal( + StratumConnection worker, string nonce) + { + var context = worker.ContextAs(); + var extranonceBytes = context.ExtraNonce1.HexToByteArray(); + var nonceBytes = nonce.HexToByteArray(); + + var coinbaseBytes = SerializeCoinbase(extranonceBytes, nonceBytes); + Span hashCoinbaseBytes = stackalloc byte[XelisConstants.HashSize]; + + if(BlockTemplate.Algorithm == XelisConstants.AlgorithmXelisHashV2) + xelisHashV2.Digest(coinbaseBytes, hashCoinbaseBytes); + else + xelisHash.Digest(coinbaseBytes, hashCoinbaseBytes); + + var targetHashCoinbaseBytes = new Target(new BigInteger(hashCoinbaseBytes, true, true)); + var hashCoinbaseBytesValue = targetHashCoinbaseBytes.ToUInt256(); + //throw new StratumException(StratumError.LowDifficultyShare, $"nonce: {nonce} ||| hashCoinbaseBytes: {hashCoinbaseBytes.ToHexString()} [Reverse: {hashCoinbaseBytes.ToNewReverseArray().ToHexString()}] ||| BigInteger: {targetHashCoinbaseBytes.ToBigInteger()} ||| Target: {hashCoinbaseBytesValue} [isBlockCandidate: {hashCoinbaseBytesValue <= blockTargetValue} - stratum: {new Target(new BigInteger(XelisUtils.DifficultyToTarget(context.Difficulty), true, true)).ToUInt256()} - blockTemplate: {blockTargetValue}] ||| shareDiff: {(double) new BigRational(XelisConstants.Diff1Target, targetHashCoinbaseBytes.ToBigInteger()) * shareMultiplier} [isStratumCandidate: {hashCoinbaseBytesValue <= new Target(new BigInteger(XelisUtils.DifficultyToTarget(context.Difficulty), true, true)).ToUInt256()} - stratum: {context.Difficulty} - blockTemplate: {Difficulty}]"); + + // calc share-diff + var shareDiff = (double) new BigRational(XelisConstants.Diff1Target, targetHashCoinbaseBytes.ToBigInteger()) * shareMultiplier; + + // diff check + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; + + // check if the share meets the much harder block difficulty (block candidate) + var isBlockCandidate = hashCoinbaseBytesValue <= blockTargetValue; + //var isBlockCandidate = XelisUtils.CheckDiff(hashCoinbaseBytes, blockTargetBytes); + + // test if share meets at least workers current difficulty + 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) + { + ratio = shareDiff / context.PreviousDifficulty.Value; + + if(ratio < 0.99) + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share [{shareDiff}]"); + + // use previous difficulty + stratumDifficulty = context.PreviousDifficulty.Value; + } + + else + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share [{shareDiff}]"); + } + + var result = new Share + { + BlockHeight = (long) BlockHeader.TopoHeight, + NetworkDifficulty = Difficulty, + Difficulty = stratumDifficulty, + }; + + if(isBlockCandidate) + { + result.IsBlockCandidate = true; + + Span blockHashBytes = stackalloc byte[XelisConstants.HashSize]; + blake3Hasher.Digest(coinbaseBytes, blockHashBytes); + + result.BlockHash = blockHashBytes.ToHexString(); + + var blockHeaderBytes = SerializeHeader(extranonceBytes, nonceBytes); + BlockHeader.Template = blockHeaderBytes.ToHexString(); + + return result; + } + + return result; + } + + public virtual void Init(GetBlockHeaderResponse blockHeader, GetBlockTemplateResponse blockTemplate, string jobId, IMasterClock clock, string network, double shareMultiplier, string prevHash) + { + Contract.RequiresNonNull(blockHeader); + Contract.RequiresNonNull(blockTemplate); + Contract.RequiresNonNull(clock); + Contract.RequiresNonNull(network); + Contract.Requires(!string.IsNullOrEmpty(jobId)); + Contract.RequiresNonNull(shareMultiplier); + + this.clock = clock; + BlockHeader = blockHeader; + BlockTemplate = blockTemplate; + JobId = jobId; + this.shareMultiplier = shareMultiplier; + + this.network = network; + + Difficulty = BlockTemplate.Difficulty; + blockTargetBytes = XelisUtils.DifficultyToTarget(BlockTemplate.Difficulty); + blockTargetValue = new Target(new BigInteger(blockTargetBytes, true, true)).ToUInt256(); + + PrevHash = prevHash; + prevHashBytes = PrevHash.HexToByteArray(); + + var blockHeaderBytes = BlockHeader.Template.HexToByteArray(); + var blockTemplateBytes = BlockTemplate.Template.HexToByteArray(); + + versionBytes = blockHeaderBytes.Take(XelisConstants.BlockHeaderOffsetHeight - XelisConstants.BlockHeaderOffsetVersion).ToArray(); + heightBytes = blockHeaderBytes.Skip(XelisConstants.BlockHeaderOffsetHeight).Take(XelisConstants.BlockHeaderOffsetTimestamp - XelisConstants.BlockHeaderOffsetHeight).ToArray(); + + //nTimeBytes = (BitConverter.IsLittleEndian ? BitConverter.GetBytes(XelisUtils.UnixTimeStamp(clock.Now)).ReverseInPlace() : BitConverter.GetBytes(XelisUtils.UnixTimeStamp(clock.Now))); // xelis_daemon expects a big endian format. + nTimeBytes = blockTemplateBytes.Skip(XelisConstants.BlockTemplateOffsetTimestamp).Take(XelisConstants.BlockTemplateOffsetNonce - XelisConstants.BlockTemplateOffsetTimestamp).ToArray(); + + extraNonceBytes = blockTemplateBytes.Skip(XelisConstants.BlockTemplateOffsetExtraNonce).Take(XelisConstants.BlockTemplateOffsetMinerPublicKey - XelisConstants.BlockTemplateOffsetExtraNonce).ToArray(); + + tipsCountBytes = blockHeaderBytes.Skip(XelisConstants.BlockHeaderOffsetTipsCount).Take(XelisConstants.BlockHeaderOffsetTips - XelisConstants.BlockHeaderOffsetTipsCount).ToArray(); + var tipsCount = uint.Parse(tipsCountBytes.ToHexString(), NumberStyles.HexNumber); + if(tipsCount > 0) + tipsBytes = blockHeaderBytes.Skip(XelisConstants.BlockHeaderOffsetTips).Take(XelisConstants.HashSize * (int) tipsCount).ToArray(); + + transactionsCountBytes = blockHeaderBytes.Skip(XelisConstants.BlockHeaderOffsetTips + (XelisConstants.HashSize * (int) tipsCount)).Take(XelisConstants.BlockHeaderSizeTransactionsCount).ToArray(); + var transactionsCount = uint.Parse(transactionsCountBytes.ToHexString(), NumberStyles.HexNumber); + if(transactionsCount > 0) + transactionsBytes = blockHeaderBytes.Skip(XelisConstants.BlockHeaderOffsetTips + (XelisConstants.HashSize * (int) tipsCount) + XelisConstants.BlockHeaderSizeTransactionsCount).Take(XelisConstants.HashSize * (int) transactionsCount).ToArray(); + + minerPublicKeyBytes = blockTemplateBytes.Skip(XelisConstants.BlockTemplateOffsetMinerPublicKey).Take(blockTemplateBytes.Length - XelisConstants.BlockTemplateOffsetMinerPublicKey).ToArray(); + + jobParams = new object[] + { + JobId, + nTimeBytes.ToHexString(), + PrevHash, + BlockTemplate.Algorithm, + false + }; + } + + public virtual object GetJobParams(bool isNew) + { + jobParams[^1] = isNew; + return jobParams; + } + + protected virtual bool RegisterSubmit(string extraNonce1, string nonce) + { + var key = new StringBuilder() + .Append(extraNonce1) + .Append(nonce) + .ToString(); + + return submissions.TryAdd(key, true); + } + + public virtual Share ProcessShare(StratumConnection worker, + string nonce) + { + Contract.Requires(!string.IsNullOrEmpty(nonce)); + + var context = worker.ContextAs(); + + // validate nonce + if(nonce.Length != XelisConstants.NonceLength) + throw new StratumException(StratumError.Other, "incorrect size of nonce"); + + // dupe check + if(!RegisterSubmit(context.ExtraNonce1, nonce)) + throw new StratumException(StratumError.DuplicateShare, "duplicate"); + + return ProcessShareInternal(worker, nonce); + } + + #endregion // API-Surface +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Xelis/XelisJobManager.cs b/src/Miningcore/Blockchain/Xelis/XelisJobManager.cs new file mode 100644 index 0000000000..d27ea09d5a --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/XelisJobManager.cs @@ -0,0 +1,651 @@ +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Text; +using Autofac; +using Miningcore.Blockchain.Xelis.Configuration; +using Miningcore.Blockchain.Xelis.DaemonRequests; +using Miningcore.Blockchain.Xelis.DaemonResponses; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.JsonRpc; +using Miningcore.Messaging; +using Miningcore.Mining; +using Miningcore.Native; +using Miningcore.Notifications.Messages; +using Miningcore.Rest; +using Miningcore.Rpc; +using Miningcore.Stratum; +using Miningcore.Time; +using Miningcore.Util; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NLog; +using Contract = Miningcore.Contracts.Contract; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Xelis; + +public class XelisJobManager : JobManagerBase +{ + public XelisJobManager( + IComponentContext ctx, + IMasterClock clock, + IMessageBus messageBus, + IExtraNonceProvider extraNonceProvider) : + base(ctx, messageBus) + { + Contract.RequiresNonNull(ctx); + Contract.RequiresNonNull(clock); + Contract.RequiresNonNull(messageBus); + Contract.RequiresNonNull(extraNonceProvider); + + this.clock = clock; + this.extraNonceProvider = extraNonceProvider; + } + + private XelisCoinTemplate coin; + private DaemonEndpointConfig[] daemonEndpoints; + private DaemonEndpointConfig[] walletDaemonEndpoints; + private RpcClient rpc; + protected RpcClient rpcWallet; + private string network; + private readonly IExtraNonceProvider extraNonceProvider; + private readonly IMasterClock clock; + private XelisPoolConfigExtra extraPoolConfig; + protected int maxActiveJobs; + public string poolPublicKey { get; protected set; } + + private async Task<(RpcResponse, RpcResponse)> GetBlockTemplateAsync(CancellationToken ct) + { + var getBlockHeaderRequest = new GetBlockHeaderRequest + { + Address = poolConfig.Address + }; + + var getBlockHeaderResponse = await rpc.ExecuteAsync(logger, XelisCommands.GetBlockHeader, ct, getBlockHeaderRequest); + + var getBlockTemplateRequest = new GetBlockTemplateRequest + { + BlockHeader = getBlockHeaderResponse?.Response.Template, + Address = poolConfig.Address + }; + + var getBlockTemplateResponse = await rpc.ExecuteAsync(logger, XelisCommands.GetBlockTemplate, ct, getBlockTemplateRequest); + + return (getBlockHeaderResponse, getBlockTemplateResponse); + } + + protected async Task UpdateJob(CancellationToken ct, string via = null) + { + try + { + var (responseBlockHeader, responseBlockTemplate) = await GetBlockTemplateAsync(ct); + if(responseBlockHeader.Error != null || responseBlockTemplate.Error != null) + return false; + + var blockHeader = responseBlockHeader.Response; + var blockTemplate = responseBlockTemplate.Response; + var job = currentJob; + + logger.Debug(() => $" blockHeader.TopoHeight [{blockHeader.TopoHeight}] || blockTemplate.Difficulty [{blockTemplate.Difficulty}]] || blockTemplate.Template [{blockTemplate.Template}]"); + + var newHash = blockTemplate.Template.HexToByteArray().AsSpan().Slice(XelisConstants.BlockTemplateOffsetBlockHeaderWork, XelisConstants.BlockTemplateOffsetTimestamp).ToHexString(); + var isNew = currentJob == null || + (newHash != job?.PrevHash); + + if(isNew) + { + messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); + + // update job + job = new XelisJob(); + job.Init(blockHeader, blockTemplate, NextJobId(), clock, network, ShareMultiplier, newHash); + + logger.Debug(() => $"blockTargetValue: {job.blockTargetValue}"); + + if(via != null) + logger.Info(() => $"Detected new block {blockHeader.TopoHeight} [{via}]"); + else + logger.Info(() => $"Detected new block {blockHeader.TopoHeight}"); + + // update stats + if (job.BlockHeader.TopoHeight > BlockchainStats.BlockHeight) + { + BlockchainStats.LastNetworkBlockTime = clock.Now; + BlockchainStats.BlockHeight = job.BlockHeader.TopoHeight; // Miningpolstats seems to track "TopoHeight" not "Height" :/ + BlockchainStats.NetworkDifficulty = job.Difficulty; + } + + currentJob = job; + } + + else + { + if(via != null) + logger.Debug(() => $"Template update {blockHeader.TopoHeight} [{via}]"); + else + logger.Debug(() => $"Template update {blockHeader.TopoHeight}"); + } + + return isNew; + } + + catch(OperationCanceledException) + { + // ignored + } + + catch(Exception ex) + { + logger.Error(ex, () => $"Error during {nameof(UpdateJob)}"); + } + + return false; + } + + private async Task UpdateNetworkStatsAsync(CancellationToken ct) + { + var hashrate = await rpc.ExecuteAsync(logger, XelisCommands.GetDifficulty, ct); + if(hashrate.Error == null) + BlockchainStats.NetworkHashrate = hashrate.Response.Hashrate; + + var status = await rpc.ExecuteAsync(logger, XelisCommands.GetStatus, ct); + if(status.Error == null) + BlockchainStats.ConnectedPeers = status.Response.PeerCount; + } + + private async Task ShowDaemonSyncProgressAsync(CancellationToken ct) + { + var status = await rpc.ExecuteAsync(logger, XelisCommands.GetStatus, ct); + if(status.Error == null) + { + var percent = (double) status.Response.TopoHeight / status.Response.BestTopoHeight * 100; + + logger.Info(() => $"Daemon has downloaded {percent:0.00}% of blockchain from {status.Response.PeerCount} peer(s)"); + } + } + + protected async Task SubmitBlockAsync(Share share, GetBlockHeaderResponse blockHeader, CancellationToken ct) + { + Contract.RequiresNonNull(blockHeader); + + var block = new SubmitBlockRequest + { + BlockTemplate = blockHeader.Template + }; + + var response = await rpc.ExecuteAsync(logger, XelisCommands.SubmitBlock, ct, block); + if(response.Error != null) + { + logger.Warn(() => $"Block {share.BlockHeight} submission failed with: {response.Error.Message} (Code {response.Error.Code})"); + 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}: {response.Error.Message} (Code {response.Error.Code})")); + return false; + } + + logger.Debug(() => $"{XelisCommands.SubmitBlock}': {response.Response}"); + + return (bool)response.Response; + } + + protected object GetJobParamsForStratum(bool isNew) + { + var job = currentJob; + return job?.GetJobParams(isNew); + } + + public override XelisJob GetJobForStratum() + { + var job = currentJob; + return job; + } + + #region API-Surface + + public IObservable Jobs { get; private set; } + public BlockchainStats BlockchainStats { get; } = new(); + public string Network => network; + + public XelisCoinTemplate Coin => coin; + + public override void Configure(PoolConfig pc, ClusterConfig cc) + { + coin = pc.Template.As(); + + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); + + maxActiveJobs = extraPoolConfig?.MaxActiveJobs ?? 8; + + // extract standard daemon endpoints + daemonEndpoints = pc.Daemons + .Where(x => string.IsNullOrEmpty(x.Category)) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = XelisConstants.DaemonRpcLocation; + + return x; + }) + .ToArray(); + + if(cc.PaymentProcessing?.Enabled == true && pc.PaymentProcessing?.Enabled == true) + { + // extract wallet daemon endpoints + walletDaemonEndpoints = pc.Daemons + .Where(x => x.Category?.ToLower() == XelisConstants.WalletDaemonCategory) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = XelisConstants.DaemonRpcLocation; + + return x; + }) + .ToArray(); + + if(walletDaemonEndpoints.Length == 0) + throw new PoolStartupException("Wallet-RPC daemon is not configured (Daemon configuration for xelis-pools require an additional entry of category 'wallet' pointing to the wallet http port: https://docs.xelis.io/getting-started/configuration#wallet )", pc.Id); + } + + base.Configure(pc, cc); + } + + public object[] GetSubscriberData(StratumConnection worker) + { + Contract.RequiresNonNull(worker); + + var context = worker.ContextAs(); + + // assign unique ExtraNonce1 to worker (miner) + context.ExtraNonce1 = extraNonceProvider.Next(); + + // setup response data + var responseData = new object[] + { + context.ExtraNonce1, + XelisConstants.ExtranoncePlaceHolderLength, + }; + + return responseData; + } + + public int GetExtraNonce1Size() + { + return extraPoolConfig?.ExtraNonce1Size ?? 32; + } + + public virtual async ValueTask SubmitShareAsync(StratumConnection worker, object submission, + CancellationToken ct) + { + Contract.RequiresNonNull(worker); + Contract.RequiresNonNull(submission); + + if(submission is not object[] submitParams) + throw new StratumException(StratumError.Other, "invalid params"); + + var context = worker.ContextAs(); + + // extract params + var jobId = submitParams[1] as string; + var nonce = submitParams[2] as string; + + XelisJob job; + + lock(context) + { + job = context.GetJob(jobId); + + if(job == null) + logger.Warn(() => $"[{context.Miner}] => jobId: {jobId} - Last known job: {context.validJobs.ToArray().FirstOrDefault()?.JobId}"); + } + + if(job == null) + throw new StratumException(StratumError.JobNotFound, "job not found"); + + // validate & process + var share = job.ProcessShare(worker, nonce); + + // enrich share with common data + share.PoolId = poolConfig.Id; + share.IpAddress = worker.RemoteEndpoint.Address.ToString(); + share.Miner = context.Miner; + share.Worker = context.Worker; + share.UserAgent = context.UserAgent; + share.Source = clusterConfig.ClusterName; + share.Created = clock.Now; + + // if block candidate, submit & check if accepted by network + if(share.IsBlockCandidate) + { + logger.Info(() => $"Submitting block {share.BlockHeight} [{share.BlockHash}][{job.BlockHeader.Template}]"); + + var acceptResponse = await SubmitBlockAsync(share, job.BlockHeader, ct); + + // is it still a block candidate? + share.IsBlockCandidate = acceptResponse; + + if(share.IsBlockCandidate) + { + logger.Info(() => $"Daemon accepted block {share.BlockHeight} [{share.BlockHash}] submitted by {context.Miner}"); + + OnBlockFound(); + + // persist the nonce to make block unlocking a bit more reliable + share.TransactionConfirmationData = nonce; + } + + else + { + // clear fields that no longer apply + share.TransactionConfirmationData = null; + } + } + + return share; + } + + public async Task NormalizeAddressAsync(string address, CancellationToken ct) + { + if(string.IsNullOrEmpty(address)) + return address; + + var splitAddressRequest = new SplitAddressRequest + { + Address = address + }; + + var response = await rpc.ExecuteAsync(logger, XelisCommands.SplitAddress, ct, splitAddressRequest); + if(response.Error != null) + { + logger.Debug(() => $"'{address}': {response.Error.Message} (Code {response.Error.Code})"); + return address; + } + + return response.Response.Address; + } + + public async Task ValidateAddressAsync(string address, CancellationToken ct) + { + if(string.IsNullOrEmpty(address)) + return false; + + var validateAddressRequest = new ValidateAddressRequest + { + Address = address + }; + + var response = await rpc.ExecuteAsync(logger, XelisCommands.ValidateAddress, ct, validateAddressRequest); + if(response.Error != null) + { + logger.Warn(() => $"'{address}': {response.Error.Message} (Code {response.Error.Code})"); + return false; + } + + return response.Response.IsValid; + } + + public double ShareMultiplier => coin.ShareMultiplier; + + #endregion // API-Surface + + #region Overrides + + protected override void ConfigureDaemons() + { + var jsonSerializerSettings = ctx.Resolve(); + + rpc = new RpcClient(daemonEndpoints.First(), jsonSerializerSettings, messageBus, poolConfig.Id); + + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + // extract wallet daemon endpoints + var walletDaemonEndpoints = poolConfig.Daemons + .Where(x => x.Category?.ToLower() == XelisConstants.WalletDaemonCategory) + .ToArray(); + + if(walletDaemonEndpoints.Length == 0) + throw new PoolStartupException("Wallet-RPC daemon is not configured (Daemon configuration for xelis-pools require an additional entry of category 'wallet' pointing to the wallet http port: https://docs.xelis.io/getting-started/configuration#wallet )", poolConfig.Id); + + rpcWallet = new RpcClient(walletDaemonEndpoints.First(), jsonSerializerSettings, messageBus, poolConfig.Id); + } + } + + protected override async Task AreDaemonsHealthyAsync(CancellationToken ct) + { + logger.Debug(() => $"Checking if '{XelisCommands.DaemonName}' daemon is healthy..."); + + // test daemon + var info = await rpc.ExecuteAsync(logger, XelisCommands.GetChainInfo, ct); + if(info.Error != null) + { + logger.Warn(() => $"'{XelisCommands.GetChainInfo}': {info.Error.Message} (Code {info.Error.Code})"); + return false; + } + + // update stats + if(!string.IsNullOrEmpty(info.Response.Version)) + BlockchainStats.NodeVersion = info.Response.Version; + + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + logger.Debug(() => "Checking if '{XelisWalletCommands.DaemonName}' daemon is healthy..."); + + // test wallet daemon + var balance = await rpcWallet.ExecuteAsync(logger, XelisWalletCommands.GetBalance, ct); + + if(balance.Error != null) + logger.Debug(() => $"'{XelisWalletCommands.GetBalance}': {balance.Error.Message} (Code {balance.Error.Code})"); + + return balance.Error == null; + } + + return true; + } + + protected override async Task AreDaemonsConnectedAsync(CancellationToken ct) + { + logger.Debug(() => $"Checking if '{XelisCommands.DaemonName}' daemon is connected..."); + + var status = await rpc.ExecuteAsync(logger, XelisCommands.GetStatus, ct); + if(status.Error != null) + { + logger.Warn(() => $"'{XelisCommands.GetStatus}': {status.Error.Message} (Code {status.Error.Code})"); + return false; + } + + return status.Response.PeerCount > 0; + } + + protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) + { + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(5)); + + logger.Debug(() => $"Checking if '{XelisCommands.DaemonName}' daemon is synched..."); + + var syncPendingNotificationShown = false; + + do + { + try + { + var status = await rpc.ExecuteAsync(logger, XelisCommands.GetStatus, ct); + if(status.Error != null) + logger.Warn(() => $"'{XelisCommands.GetStatus}': {status.Error.Message} (Code {status.Error.Code})"); + + if(status.Response.BestTopoHeight <= status.Response.MedianTopoHeight) + { + logger.Info(() => $"'{XelisCommands.DaemonName}' daemon synched with blockchain"); + break; + } + } + + catch(Exception e) + { + logger.Error(e); + } + + if(!syncPendingNotificationShown) + { + logger.Info(() => "Daemon is still syncing with network. Manager will be started once synced."); + syncPendingNotificationShown = true; + } + + await ShowDaemonSyncProgressAsync(ct); + } while(await timer.WaitForNextTickAsync(ct)); + } + + protected override async Task PostStartInitAsync(CancellationToken ct) + { + // validate pool address + if(string.IsNullOrEmpty(poolConfig.Address)) + throw new PoolStartupException("Pool address is not configured", poolConfig.Id); + + var info = await rpc.ExecuteAsync(logger, XelisCommands.GetChainInfo, ct); + if(info.Error != null) + throw new PoolStartupException("Init RPC failed...", poolConfig.Id); + + network = info.Response.Network; + + // update stats + BlockchainStats.RewardType = "POW"; + BlockchainStats.NetworkType = network; + + var validateAddressRequest = new ValidateAddressRequest + { + Address = poolConfig.Address + }; + + var validateAddress = await rpc.ExecuteAsync(logger, XelisCommands.ValidateAddress, ct, validateAddressRequest); + if(validateAddress.Error != null) + throw new PoolStartupException($"Pool address '{poolConfig.Address}': {validateAddress.Error.Message} (Code {validateAddress.Error.Code})", poolConfig.Id); + + var extractKeyFromAddressRequest = new ExtractKeyFromAddressRequest + { + Address = poolConfig.Address + }; + + var extractKeyFromAddress = await rpc.ExecuteAsync(logger, XelisCommands.ExtractKeyFromAddress, ct, extractKeyFromAddressRequest); + if(extractKeyFromAddress.Error != null) + throw new PoolStartupException($"Pool address public key '{poolConfig.Address}': {extractKeyFromAddress.Error} (Code {extractKeyFromAddress.Error.Code})", poolConfig.Id); + + logger.Info(() => $"Pool address public key: {extractKeyFromAddress.Response.PublicKey}"); + poolPublicKey = extractKeyFromAddress.Response.PublicKey; + + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + // validate wallet address + var walletAddress = await rpcWallet.ExecuteAsync(logger, XelisWalletCommands.GetAddress, ct); + if(walletAddress.Error != null) + throw new PoolStartupException($"'{XelisWalletCommands.GetAddress}': {walletAddress.Error.Message} (Code {walletAddress.Error.Code})", poolConfig.Id); + + if(walletAddress.Response != poolConfig.Address) + throw new PoolStartupException($"Wallet address [{walletAddress.Response}] does not match pool address: {poolConfig.Address}", poolConfig.Id); + } + + await UpdateNetworkStatsAsync(ct); + + // Periodically update network stats + Observable.Interval(TimeSpan.FromMinutes(1)) + .Select(via => Observable.FromAsync(() => + Guard(()=> UpdateNetworkStatsAsync(ct), + ex=> logger.Error(ex)))) + .Concat() + .Subscribe(); + + SetupJobUpdates(ct); + } + + protected virtual void SetupJobUpdates(CancellationToken ct) + { + var pollingInterval = poolConfig?.BlockRefreshInterval ?? 0; + + var blockSubmission = blockFoundSubject.Synchronize(); + var pollTimerRestart = blockFoundSubject.Synchronize(); + + var triggers = new List> + { + blockSubmission.Select(_ => (JobRefreshBy.BlockFound, (string) null)) + }; + + var endpointExtra = daemonEndpoints + .Where(x => x.Extra.SafeExtensionDataAs() != null) + .Select(x=> Tuple.Create(x, x.Extra.SafeExtensionDataAs())) + .FirstOrDefault(); + + if(endpointExtra?.Item2?.PortWs.HasValue == true) + { + var (endpointConfig, extra) = endpointExtra; + + var wsEndpointConfig = new DaemonEndpointConfig + { + Host = endpointConfig.Host, + Port = extra.PortWs!.Value, + HttpPath = extra.HttpPathWs, + Ssl = extra.SslWs + }; + + logger.Info(() => $"Subscribing to WebSocket {(wsEndpointConfig.Ssl ? "wss" : "ws")}://{wsEndpointConfig.Host}:{wsEndpointConfig.Port}"); + + var subscribeRequest = new SubscribeRequest + { + Notify = XelisCommands.NotifiyNewBlock + }; + + // stream work updates + var getWorkObs = rpc.WebsocketSubscribe(logger, ct, wsEndpointConfig, XelisCommands.Subscribe, subscribeRequest) + .Publish() + .RefCount(); + + var websocketNotify = getWorkObs.Where(x => x != null) + .Publish() + .RefCount(); + + pollTimerRestart = blockSubmission.Merge(websocketNotify.Select(_ => Unit.Default)) + .Publish() + .RefCount(); + + triggers.Add(websocketNotify.Select(_ => (JobRefreshBy.WebSocket, (string) null))); + + if(pollingInterval > 0) + { + triggers.Add(Observable.Timer(TimeSpan.FromMilliseconds(pollingInterval)) + .TakeUntil(pollTimerRestart) + .Select(_ => (JobRefreshBy.Poll, (string) null)) + .Repeat()); + } + + else + { + // get initial blocktemplate + triggers.Add(Observable.Interval(TimeSpan.FromMilliseconds(1000)) + .Select(_ => (JobRefreshBy.Initial, (string) null)) + .TakeWhile(_ => !hasInitialBlockTemplate)); + } + } + + else + { + pollingInterval = pollingInterval > 0 ? pollingInterval : 1000; + + // ordinary polling (avoid this at all cost) + triggers.Add(Observable.Timer(TimeSpan.FromMilliseconds(pollingInterval)) + .TakeUntil(pollTimerRestart) + .Select(_ => (JobRefreshBy.Poll, (string) null)) + .Repeat()); + } + + Jobs = triggers.Merge() + .Select(x => Observable.FromAsync(() => UpdateJob(ct, x.Via))) + .Concat() + .Where(x => x) + .Do(x => + { + if(x) + hasInitialBlockTemplate = true; + }) + .Select(x => GetJobParamsForStratum(x)) + .Publish() + .RefCount(); + } + + #endregion // Overrides +} diff --git a/src/Miningcore/Blockchain/Xelis/XelisPayoutHandler.cs b/src/Miningcore/Blockchain/Xelis/XelisPayoutHandler.cs new file mode 100644 index 0000000000..5f7eede2c8 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/XelisPayoutHandler.cs @@ -0,0 +1,406 @@ +using System; +using System.Linq; +using Autofac; +using AutoMapper; +using Miningcore.Blockchain.Xelis.Configuration; +using Miningcore.Blockchain.Xelis.DaemonRequests; +using Miningcore.Blockchain.Xelis.DaemonResponses; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Mining; +using Miningcore.Payments; +using Miningcore.Persistence; +using Miningcore.Persistence.Model; +using Miningcore.Persistence.Repositories; +using Miningcore.Rpc; +using Miningcore.Time; +using Miningcore.Util; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Block = Miningcore.Persistence.Model.Block; +using Contract = Miningcore.Contracts.Contract; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Xelis; + +[CoinFamily(CoinFamily.Xelis)] +public class XelisPayoutHandler : PayoutHandlerBase, + IPayoutHandler +{ + public XelisPayoutHandler( + IComponentContext ctx, + IConnectionFactory cf, + IMapper mapper, + IShareRepository shareRepo, + IBlockRepository blockRepo, + IBalanceRepository balanceRepo, + IPaymentRepository paymentRepo, + IMasterClock clock, + IMessageBus messageBus) : + base(cf, mapper, shareRepo, blockRepo, balanceRepo, paymentRepo, clock, messageBus) + { + Contract.RequiresNonNull(ctx); + Contract.RequiresNonNull(balanceRepo); + Contract.RequiresNonNull(paymentRepo); + + this.ctx = ctx; + } + + protected readonly IComponentContext ctx; + private RpcClient rpcClient; + private RpcClient rpcClientWallet; + private string network; + private XelisPaymentProcessingConfigExtra extraPoolPaymentProcessingConfig; + private int minConfirmations; + + protected override string LogCategory => "Xelis Payout Handler"; + + #region IPayoutHandler + + public virtual async Task ConfigureAsync(ClusterConfig cc, PoolConfig pc, CancellationToken ct) + { + Contract.RequiresNonNull(pc); + + poolConfig = pc; + clusterConfig = cc; + extraPoolPaymentProcessingConfig = pc.PaymentProcessing.Extra.SafeExtensionDataAs(); + + logger = LogUtil.GetPoolScopedLogger(typeof(XelisPayoutHandler), pc); + + // configure standard daemon + var jsonSerializerSettings = ctx.Resolve(); + + var daemonEndpoints = pc.Daemons + .Where(x => string.IsNullOrEmpty(x.Category)) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = XelisConstants.DaemonRpcLocation; + + return x; + }) + .ToArray(); + + rpcClient = new RpcClient(daemonEndpoints.First(), jsonSerializerSettings, messageBus, pc.Id); + + // configure wallet daemon + var walletDaemonEndpoints = pc.Daemons + .Where(x => x.Category?.ToLower() == XelisConstants.WalletDaemonCategory) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = XelisConstants.DaemonRpcLocation; + + return x; + }) + .ToArray(); + + rpcClientWallet = new RpcClient(walletDaemonEndpoints.First(), jsonSerializerSettings, messageBus, pc.Id); + + var info = await rpcClient.ExecuteAsync(logger, XelisCommands.GetChainInfo, ct); + if(info.Error != null) + throw new Exception($"'{XelisCommands.DaemonName}' returned error: {info.Error.Message} (Code {info.Error.Code})"); + + network = info.Response.Network; + + // wallet daemon needs to be online + var isOnline = await rpcClientWallet.ExecuteAsync(logger, XelisWalletCommands.IsOnline, ct); + if(isOnline.Error != null) + throw new Exception($"'{XelisWalletCommands.IsOnline}': {isOnline.Error.Message} (Code {isOnline.Error.Code})"); + + // wallet daemon is offline + if(!(bool)isOnline.Response) + { + logger.Warn(() => $"[{LogCategory}] '{XelisWalletCommands.DaemonName}' is offline..."); + + var setOnlineMode = await rpcClientWallet.ExecuteAsync(logger, XelisWalletCommands.SetOnlineMode, ct); + if(setOnlineMode.Error != null) + throw new Exception($"'{XelisWalletCommands.SetOnlineMode}': {setOnlineMode.Error.Message} (Code {setOnlineMode.Error.Code})"); + + // wallet daemon is online + if((bool)setOnlineMode.Response) + logger.Info(() => $"[{LogCategory}] '{XelisWalletCommands.DaemonName}' is now online..."); + } + + minConfirmations = extraPoolPaymentProcessingConfig?.MinimumConfirmations ?? (network == "mainnet" ? 60 : 50); + } + + public virtual async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, CancellationToken ct) + { + Contract.RequiresNonNull(poolConfig); + Contract.RequiresNonNull(blocks); + + if(blocks.Length == 0) + return blocks; + + var info = await rpcClient.ExecuteAsync(logger, XelisCommands.GetChainInfo, ct); + if(info.Error != null) + { + logger.Warn(() => $"[{LogCategory}] '{XelisCommands.GetChainInfo}': {info.Error.Message} (Code {info.Error.Code})"); + return blocks; + } + + var coin = poolConfig.Template.As(); + var pageSize = 100; + var pageCount = (int) Math.Ceiling(blocks.Length / (double) pageSize); + var result = new List(); + + for(var i = 0; i < pageCount; i++) + { + // get a page full of blocks + var page = blocks + .Skip(i * pageSize) + .Take(pageSize) + .ToArray(); + + for(var j = 0; j < page.Length; j++) + { + var block = page[j]; + + var getBlockByHashRequest = new GetBlockByHashRequest + { + Hash = block.Hash + }; + + var response = await rpcClient.ExecuteAsync(logger, XelisCommands.GetBlockByHash, ct, getBlockByHashRequest); + if(response.Error != null) + { + logger.Warn(() => $"[{LogCategory}] '{XelisCommands.GetBlockByHash}': {response.Error.Message} (Code {response.Error.Code})"); + + // we lost that battle + if(response.Error.Code == (int)XelisRPCErrorCode.RPC_INVALID_PARAMS) + { + result.Add(block); + + block.Status = BlockStatus.Orphaned; + block.Reward = 0; + + logger.Info(() => $"[{LogCategory}] Block {block.BlockHeight} classified as orphaned because it's not on chain"); + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + } + } + + // we lost that battle + else if(response.Response.Miner != poolConfig.Address) + { + result.Add(block); + + block.Status = BlockStatus.Orphaned; + block.Reward = 0; + + logger.Info(() => $"[{LogCategory}] Block {block.BlockHeight} [Type: {response.Response.BlockType}] classified as orphaned because another miner [{response.Response.Miner}] was rewarded"); + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + } + else + { + logger.Info(() => $"[{LogCategory}] Block {block.BlockHeight} [Type: {response.Response.BlockType}] uses a custom minimum confirmations calculation [{minConfirmations}]"); + + block.ConfirmationProgress = Math.Min(1.0d, (double) (info.Response.TopoHeight - block.BlockHeight) / minConfirmations); + + result.Add(block); + + messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); + + // matured and spendable? + if(block.ConfirmationProgress >= 1) + { + block.ConfirmationProgress = 1; + + block.Reward = (decimal) response.Response.MinerReward / XelisConstants.SmallestUnit; + + // security + if (block.Reward > 0) + { + block.Status = BlockStatus.Confirmed; + + logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} [Type: {response.Response.BlockType}] worth {FormatAmount(block.Reward)}"); + } + else + { + block.Status = BlockStatus.Orphaned; + block.Reward = 0; + } + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + } + } + } + } + + return result.ToArray(); + } + + public virtual async Task PayoutAsync(IMiningPool pool, Balance[] balances, CancellationToken ct) + { + Contract.RequiresNonNull(balances); + + // ensure we have enough peers + var enoughPeers = await EnsureDaemonsSynchedAsync(ct); + if(!enoughPeers) + return; + + // build args + var amounts = balances + .Where(x => x.Amount > 0) + .ToDictionary(x => x.Address, x => x.Amount); + + if(amounts.Count == 0) + return; + + var coin = poolConfig.Template.As(); + + var balancesTotal = amounts.Sum(x => x.Value); + logger.Info(() => $"[{LogCategory}] Paying {FormatAmount(balancesTotal)} to {balances.Length} addresses"); + + logger.Info(() => $"[{LogCategory}] Validating addresses..."); + foreach(var pair in amounts) + { + var validateAddressRequest = new ValidateAddressRequest + { + Address = pair.Key + }; + + var validateAddress = await rpcClient.ExecuteAsync(logger, XelisCommands.ValidateAddress, ct, validateAddressRequest); + if(validateAddress.Error != null) + logger.Warn(()=> $"[{LogCategory}] Address {pair.Key} is not valid: {validateAddress.Error.Message} (Code {validateAddress.Error.Code})"); + } + + var responseBalance = await rpcClientWallet.ExecuteAsync(logger, XelisWalletCommands.GetBalance, ct); + if(responseBalance.Error != null) + { + logger.Warn(()=> $"[{LogCategory}] '{XelisWalletCommands.GetBalance}': {responseBalance.Error.Message} (Code {responseBalance.Error.Code})"); + return; + } + + var walletBalance = Convert.ToDecimal(responseBalance.Response) / XelisConstants.SmallestUnit; + + logger.Info(() => $"[{LogCategory}] Current wallet balance - Total: [{FormatAmount(walletBalance)}]"); + + // bail if balance does not satisfy payments + if(walletBalance < balancesTotal) + { + logger.Warn(() => $"[{LogCategory}] Wallet balance currently short of {FormatAmount(balancesTotal - walletBalance)}. Will try again"); + return; + } + + var pageSize = extraPoolPaymentProcessingConfig?.MaximumDestinationPerTransfer ?? XelisConstants.MaximumDestinationPerTransfer; + var pageCount = (int) Math.Ceiling((double) balances.Length / pageSize); + + logger.Info(() => $"[{LogCategory}] Maximum of simultaneous destination address in a single transaction: {pageSize}"); + + for(var i = 0; i < pageCount; i++) + { + logger.Info(() => $"[{LogCategory}] Processing batch {i + 1}/{pageCount}"); + + var page = balances + .Skip(i * pageSize) + .Take(pageSize) + .ToArray(); + + var buildTransactionRequest = new BuildTransactionRequest + { + Transfers = page + .Where(x => x.Amount > 0) + .Select(x => + { + return new BuildTransactionTransfer + { + Destination = x.Address, + Asset = XelisConstants.TransactionDefaultAsset, + Amount = (ulong) Math.Floor(x.Amount * XelisConstants.SmallestUnit) + }; + }).ToArray() + }; + + if(extraPoolPaymentProcessingConfig?.KeepTransactionFees == true) + { + var estimateFeesRequest = new EstimateFeesRequest + { + Transfers = buildTransactionRequest.Transfers + }; + + var estimateFeesResponse = await rpcClientWallet.ExecuteAsync(logger, XelisWalletCommands.EstimateFees, ct, estimateFeesRequest); + if(estimateFeesResponse.Error != null) + { + logger.Warn(()=> $"[{LogCategory}] '{XelisWalletCommands.EstimateFees}': {estimateFeesResponse.Error.Message} (Code {estimateFeesResponse.Error.Code})"); + continue; + } + + var estimatedTransactionFees = Convert.ToDecimal(estimateFeesResponse.Response) / XelisConstants.SmallestUnit; + logger.Info(() => $"[{LogCategory}] Estimated transaction fees: {FormatAmount(estimatedTransactionFees)}"); + + logger.Debug(() => $"[{LogCategory}] Pool does not pay the transaction fee, so each address will have its payout deducted with [{FormatAmount(estimatedTransactionFees / page.Length)}]"); + + buildTransactionRequest = new BuildTransactionRequest + { + Transfers = page + .Where(x => x.Amount > 0) + .Select(x => + { + return new BuildTransactionTransfer + { + Destination = x.Address, + Asset = XelisConstants.TransactionDefaultAsset, + Amount = (ulong) Math.Floor((x.Amount > (estimatedTransactionFees / page.Length) ? x.Amount - (estimatedTransactionFees / page.Length) : x.Amount) * XelisConstants.SmallestUnit) + }; + }).ToArray() + }; + + buildTransactionRequest.Fee = new BuildTransactionFee + { + Amount = (ulong) (estimatedTransactionFees * XelisConstants.SmallestUnit) + }; + } + + var buildTransactionResponse = await rpcClientWallet.ExecuteAsync(logger, XelisWalletCommands.BuildTransaction, ct, buildTransactionRequest); + if(buildTransactionResponse.Error != null) + { + logger.Error(()=> $"[{LogCategory}] '{XelisWalletCommands.BuildTransaction}': {buildTransactionResponse.Error.Message} (Code {buildTransactionResponse.Error.Code})"); + NotifyPayoutFailure(poolConfig.Id, page, $"Daemon command '{XelisWalletCommands.BuildTransaction}' returned error: {buildTransactionResponse.Error.Message} code {buildTransactionResponse.Error.Code}", null); + continue; + } + + if(string.IsNullOrEmpty(buildTransactionResponse.Response.Hash)) + { + logger.Warn(() => $"[{LogCategory}] Payment transaction failed to return a transaction id"); + continue; + } + else + { + // payment successful + var finalTransactionFees = (decimal) buildTransactionResponse.Response.Fee / XelisConstants.SmallestUnit; + + logger.Info(() => $"[{LogCategory}] Payment transaction id: {buildTransactionResponse.Response.Hash} || Payment transaction fees: {FormatAmount(finalTransactionFees)}"); + + await PersistPaymentsAsync(page, buildTransactionResponse.Response.Hash); + NotifyPayoutSuccess(poolConfig.Id, page, new[] { buildTransactionResponse.Response.Hash }, finalTransactionFees); + } + } + } + + public double AdjustBlockEffort(double effort) + { + return effort; + } + + #endregion // IPayoutHandler + + private async Task EnsureDaemonsSynchedAsync(CancellationToken ct) + { + // ensure we have enough peers + var status = await rpcClient.ExecuteAsync(logger, XelisCommands.GetStatus, ct); + if(status.Error != null) + { + logger.Warn(() => $"'{XelisCommands.GetStatus}': {status.Error.Message} (Code {status.Error.Code})"); + return false; + } + + if(network.ToLower() == "mainnet") + return status.Response.PeerCount > 0; + else + return status.Response.PeerCount >= 0; + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Xelis/XelisPool.cs b/src/Miningcore/Blockchain/Xelis/XelisPool.cs new file mode 100644 index 0000000000..3b2407bc5d --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/XelisPool.cs @@ -0,0 +1,434 @@ +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using Autofac; +using AutoMapper; +using Microsoft.IO; +using Miningcore.Blockchain.Xelis; +using Miningcore.Blockchain.Xelis.Configuration; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.JsonRpc; +using Miningcore.Messaging; +using Miningcore.Mining; +using Miningcore.Nicehash; +using Miningcore.Notifications.Messages; +using Miningcore.Persistence; +using Miningcore.Persistence.Repositories; +using Miningcore.Stratum; +using Miningcore.Time; +using Newtonsoft.Json; +using NLog; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Xelis; + +[CoinFamily(CoinFamily.Xelis)] +public class XelisPool : PoolBase +{ + public XelisPool(IComponentContext ctx, + JsonSerializerSettings serializerSettings, + IConnectionFactory cf, + IStatsRepository statsRepo, + IMapper mapper, + IMasterClock clock, + IMessageBus messageBus, + RecyclableMemoryStreamManager rmsm, + NicehashService nicehashService) : + base(ctx, serializerSettings, cf, statsRepo, mapper, clock, messageBus, rmsm, nicehashService) + { + } + + private object currentJobParams; + private XelisJobManager manager; + private XelisPoolConfigExtra extraPoolConfig; + private XelisCoinTemplate coin; + + protected virtual async Task OnSubscribeAsync(StratumConnection connection, Timestamped tsRequest) + { + var request = tsRequest.Value; + + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + var context = connection.ContextAs(); + + var requestParams = request.ParamsAs(); + + if(requestParams?.Length < 1) + throw new StratumException(StratumError.Other, "invalid params"); + + context.UserAgent = requestParams.FirstOrDefault()?.ToString().Trim(); + + var subscriberData = manager.GetSubscriberData(connection); + var data = new object[] + { + connection.ConnectionId + } + .Concat(subscriberData) + .Concat(new object[] + { + manager.poolPublicKey + }) + .ToArray(); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(data, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); + + // setup worker context + context.IsSubscribed = true; + + // Nicehash support + var nicehashDiff = await GetNicehashStaticMinDiff(context, coin.Name, coin.GetAlgorithmName()); + + if(nicehashDiff.HasValue) + { + logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using API supplied difficulty of {nicehashDiff.Value}"); + + context.VarDiff = null; // disable vardiff + context.SetDifficulty(nicehashDiff.Value); + } + } + + protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + var context = connection.ContextAs(); + if(!context.IsSubscribed) + throw new StratumException(StratumError.NotSubscribed, "subscribe first please, we aren't savages"); + + var requestParams = request.ParamsAs(); + + if(requestParams?.Length < 1) + throw new StratumException(StratumError.Other, "invalid params"); + + var workerValue = requestParams?.Length > 0 ? requestParams[0] : null; + var workerName = requestParams?.Length > 1 ? requestParams[1] : string.Empty; + var password = requestParams?.Length > 2 ? requestParams[2] : null; + var passParts = password?.Split(PasswordControlVarsSeparator); + + // extract worker/miner + var split = workerValue?.Split('.'); + var minerName = split?.FirstOrDefault()?.Trim(); + workerName = split?.Skip(1).FirstOrDefault()?.Trim() ?? workerName; + + // assumes that minerName is an address + minerName = await manager.NormalizeAddressAsync(minerName, ct); + context.IsAuthorized = await manager.ValidateAddressAsync(minerName, ct); + + context.Miner = minerName; + context.Worker = workerName; + + if(context.IsAuthorized) + { + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(context.IsAuthorized, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + // respond + await connection.RespondAsync(response); + + // log association + logger.Info(() => $"[{connection.ConnectionId}]{(!string.IsNullOrEmpty(context.UserAgent) ? $"[{context.UserAgent}]" : string.Empty)} Authorized worker {workerValue}"); + + // extract control vars from password + var staticDiff = GetStaticDiffFromPassparts(passParts); + + // Static diff + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) + { + context.VarDiff = null; // disable vardiff + context.SetDifficulty(staticDiff.Value); + + logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); + } + + var minerJobParams = CreateWorkerJob(connection, context.IsAuthorized); + + // send intial update + await connection.NotifyAsync(XelisStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + await connection.NotifyAsync(XelisStratumMethods.MiningNotify, minerJobParams); + } + + else + { + await connection.RespondErrorAsync(StratumError.UnauthorizedWorker, "Authorization failed", request.Id, context.IsAuthorized); + + if(clusterConfig?.Banning?.BanOnLoginFailure is null or true) + { + // issue short-time ban if unauthorized to prevent DDos on daemon (validateaddress RPC) + logger.Info(() => $"[{connection.ConnectionId}]{(!string.IsNullOrEmpty(context.UserAgent) ? $"[{context.UserAgent}]" : string.Empty)} Banning unauthorized worker {minerName} for {loginFailureBanTimeout.TotalSeconds} sec"); + + banManager.Ban(connection.RemoteEndpoint.Address, loginFailureBanTimeout); + + Disconnect(connection); + } + } + } + + private object CreateWorkerJob(StratumConnection connection, bool cleanJob) + { + var context = connection.ContextAs(); + var maxActiveJobs = extraPoolConfig?.MaxActiveJobs ?? 8; + var job = manager.GetJobForStratum(); + + // update context + lock(context) + { + context.AddJob(job, maxActiveJobs); + } + + return job.GetJobParams(cleanJob); + } + + protected virtual async Task OnSubmitAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + try + { + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + // check age of submission (aged submissions are usually caused by high server load) + var requestAge = clock.Now - tsRequest.Timestamp.UtcDateTime; + + if(requestAge > maxShareAge) + { + logger.Warn(() => $"[{connection.ConnectionId}] Dropping stale share submission request (server overloaded?)"); + return; + } + + // check worker state + context.LastActivity = clock.Now; + + // validate worker + if(!context.IsAuthorized) + throw new StratumException(StratumError.UnauthorizedWorker, "unauthorized worker"); + else if(!context.IsSubscribed) + throw new StratumException(StratumError.NotSubscribed, "not subscribed"); + + var requestParams = request.ParamsAs(); + + // submit + var share = await manager.SubmitShareAsync(connection, requestParams, ct); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + // respond + await connection.RespondAsync(response); + + // publish + messageBus.SendMessage(share); + + // telemetry + PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, true); + + logger.Info(() => $"[{connection.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty * coin.ShareMultiplier, 3)}"); + + // update pool stats + if(share.IsBlockCandidate) + poolStats.LastPoolBlockTime = clock.Now; + + // update client stats + context.Stats.ValidShares++; + + await UpdateVarDiffAsync(connection, false, ct); + } + + catch(StratumException ex) + { + // telemetry + PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, false); + + // update client stats + context.Stats.InvalidShares++; + logger.Info(() => $"[{connection.ConnectionId}] Share rejected: {ex.Message} [{context.UserAgent}]"); + + // banning + ConsiderBan(connection, context, poolConfig.Banning); + + throw; + } + } + + protected virtual async Task OnNewJobAsync(object jobParams) + { + currentJobParams = jobParams; + + logger.Info(() => $"Broadcasting job {((object[]) jobParams)[0]}"); + + await Guard(() => ForEachMinerAsync(async (connection, ct) => + { + var context = connection.ContextAs(); + var minerJobParams = CreateWorkerJob(connection, (bool) ((object[]) jobParams)[^1]); + + // varDiff: if the client has a pending difficulty change, apply it now + if(context.ApplyPendingDifficulty()) + await connection.NotifyAsync(XelisStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + + // send job + await connection.NotifyAsync(XelisStratumMethods.MiningNotify, minerJobParams); + })); + } + + public override double HashrateFromShares(double shares, double interval) + { + var result = shares / interval; + + return result; + } + + public override double ShareMultiplier => coin.ShareMultiplier; + + #region Overrides + + public override void Configure(PoolConfig pc, ClusterConfig cc) + { + coin = pc.Template.As(); + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); + + base.Configure(pc, cc); + } + + protected override async Task SetupJobManager(CancellationToken ct) + { + var extraNonce1Size = extraPoolConfig?.ExtraNonce1Size ?? 32; + + manager = ctx.Resolve( + new TypedParameter(typeof(IExtraNonceProvider), new XelisExtraNonceProvider(poolConfig.Id, extraNonce1Size, clusterConfig.InstanceId))); + + manager.Configure(poolConfig, clusterConfig); + + await manager.StartAsync(ct); + + if(poolConfig.EnableInternalStratum == true) + { + disposables.Add(manager.Jobs + .Select(job => Observable.FromAsync(() => + Guard(()=> OnNewJobAsync(job), + ex=> logger.Debug(() => $"{nameof(OnNewJobAsync)}: {ex.Message}")))) + .Concat() + .Subscribe(_ => { }, ex => + { + logger.Debug(ex, nameof(OnNewJobAsync)); + })); + + // start with initial blocktemplate + await manager.Jobs.Take(1).ToTask(ct); + } + + else + { + // keep updating NetworkStats + disposables.Add(manager.Jobs.Subscribe()); + } + } + + protected override async Task InitStatsAsync(CancellationToken ct) + { + await base.InitStatsAsync(ct); + + blockchainStats = manager.BlockchainStats; + } + + protected override WorkerContextBase CreateWorkerContext() + { + return new XelisWorkerContext(); + } + + protected override async Task OnRequestAsync(StratumConnection connection, + Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + + try + { + switch(request.Method) + { + case XelisStratumMethods.Authorize: + await OnAuthorizeAsync(connection, tsRequest, ct); + break; + + case XelisStratumMethods.Subscribe: + await OnSubscribeAsync(connection, tsRequest); + break; + + case XelisStratumMethods.SubmitShare: + await OnSubmitAsync(connection, tsRequest, ct); + break; + + case XelisStratumMethods.Pong: + var context = connection.ContextAs(); + + // recognize activity + context.LastActivity = clock.Now; + break; + + case XelisStratumMethods.SubmitHashrate: + // we do nothing + break; + + default: + logger.Debug(() => $"[{connection.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); + + await connection.RespondErrorAsync(StratumError.Other, $"Unsupported request {request.Method}", request.Id); + break; + } + } + + catch(StratumException ex) + { + await connection.RespondErrorAsync(ex.Code, ex.Message, request.Id, false); + } + } + + protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, double newDiff, CancellationToken ct) + { + await base.OnVarDiffUpdateAsync(connection, newDiff, ct); + + if(connection.Context.ApplyPendingDifficulty()) + { + var minerJobParams = CreateWorkerJob(connection, (bool) ((object[]) currentJobParams)[^1]); + + // send varDiff update + await connection.NotifyAsync(XelisStratumMethods.SetDifficulty, new object[] { connection.Context.Difficulty }); + await connection.NotifyAsync(XelisStratumMethods.MiningNotify, minerJobParams); + } + } + + #endregion // Overrides +} diff --git a/src/Miningcore/Blockchain/Xelis/XelisStratumMethods.cs b/src/Miningcore/Blockchain/Xelis/XelisStratumMethods.cs new file mode 100644 index 0000000000..ff8024ee64 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/XelisStratumMethods.cs @@ -0,0 +1,57 @@ +namespace Miningcore.Blockchain.Xelis; + +/* + * Xelis Stratum RPC protocol: https://docs.xelis.io/developers-api/stratum + */ +public class XelisStratumMethods +{ + /// + /// Used to subscribe to work from a server, required before all other communication. + /// + public const string Subscribe = "mining.subscribe"; + + /// + /// Used to authorize a worker, required before any shares can be submitted. + /// + public const string Authorize = "mining.authorize"; + + /// + /// Used to push new work to the miner. + /// + public const string MiningNotify = "mining.notify"; + + /// + /// Used to submit shares + /// + public const string SubmitShare = "mining.submit"; + + /// + /// Used to signal the miner to stop submitting shares under the new difficulty. + /// + public const string SetDifficulty = "mining.set_difficulty"; + + /// + /// Used to subscribe to work from a server, required before all other communication. + /// + public const string SetExtraNonce = "mining.set_extranonce"; + + /// + /// Used to check if a miner connection is still alive. + /// + public const string Ping = "mining.ping"; + + /// + /// Used to signify that the miner connection is still alive. + /// + public const string Pong = "mining.pong"; + + /// + /// Used to send a message to the miner to print on screen. + /// + public const string Print = "mining.print"; + + /// + /// Used to submit the reported hashrate (in miner) to the pool (similar to eth_submitHashrate in ethash). + /// + public const string SubmitHashrate = "mining.hashrate"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Xelis/XelisUtils.cs b/src/Miningcore/Blockchain/Xelis/XelisUtils.cs new file mode 100644 index 0000000000..a777258c06 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/XelisUtils.cs @@ -0,0 +1,56 @@ +using System; +using System.Numerics; +using Miningcore.Extensions; + +namespace Miningcore.Blockchain.Xelis; + +public static class XelisUtils +{ + public static byte[] DifficultyToTarget(double difficulty) + { + Span paddedBytes = stackalloc byte[XelisConstants.TargetPaddingLength]; + + if(difficulty == 0.0) + return paddedBytes.ToArray(); + + var targetBigInteger = BigInteger.Multiply(BigInteger.Divide(XelisConstants.Diff1Target, new BigInteger((ulong) (difficulty * 255d))), new BigInteger(255)); + var targetBytes = targetBigInteger.ToByteArray().AsSpan(); + + var padLength = paddedBytes.Length - targetBytes.Length; + + if(padLength > 0) + targetBytes.CopyTo(paddedBytes[padLength..]); + else + targetBytes.Slice(targetBytes.Length - paddedBytes.Length, paddedBytes.Length).CopyTo(paddedBytes); + + return paddedBytes.ToArray(); + } + + public static long UnixTimeStamp(DateTime date) + { + long unixTimeStamp = date.ToUniversalTime().Ticks - new DateTime(1970, 1, 1, 0, 0, 0).Ticks; + unixTimeStamp /= TimeSpan.TicksPerMillisecond; + return unixTimeStamp; + } + + public static bool CheckDiff(Span hashBytes, double difficulty) + { + byte[] targetBytes = DifficultyToTarget(difficulty); + + return CheckDiff(hashBytes, targetBytes); + } + + public static bool CheckDiff(Span hashBytes, byte[] targetBytes) + { + for (int i = 0; i < 32; i++) + { + if (hashBytes[i] < targetBytes[i]) + return true; + + if (hashBytes[i] > targetBytes[i]) + return false; + } + + return false; + } +} diff --git a/src/Miningcore/Blockchain/Xelis/XelisWorkerContext.cs b/src/Miningcore/Blockchain/Xelis/XelisWorkerContext.cs new file mode 100644 index 0000000000..584611a449 --- /dev/null +++ b/src/Miningcore/Blockchain/Xelis/XelisWorkerContext.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; +using Miningcore.Mining; + +namespace Miningcore.Blockchain.Xelis; + +public class XelisWorkerContext : WorkerContextBase +{ + /// + /// Usually a wallet address + /// + public override string Miner { get; set; } + + /// + /// Arbitrary worker identififer for miners using multiple rigs + /// + public override string Worker { get; set; } + + /// + /// Unique value assigned per worker + /// + public string ExtraNonce1 { get; set; } + + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); + + public virtual void AddJob(XelisJob job, int maxActiveJobs) + { + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); + + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); + } + + public XelisJob GetJob(string jobId) + { + return validJobs.ToArray().FirstOrDefault(x => x.JobId == jobId); + } +} diff --git a/src/Miningcore/Blockchain/Zano/Configuration/ZanoDaemonEndpointConfigExtra.cs b/src/Miningcore/Blockchain/Zano/Configuration/ZanoDaemonEndpointConfigExtra.cs new file mode 100644 index 0000000000..327b20c702 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/Configuration/ZanoDaemonEndpointConfigExtra.cs @@ -0,0 +1,16 @@ +namespace Miningcore.Blockchain.Zano.Configuration; + +public class ZanoDaemonEndpointConfigExtra +{ + /// + /// Address of ZeroMQ block notify socket + /// Should match the value of -zmqpubhashblock daemon start parameter + /// + public string ZmqBlockNotifySocket { get; set; } + + /// + /// Optional: ZeroMQ block notify topic + /// Defaults to "hashblock" if left blank + /// + public string ZmqBlockNotifyTopic { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/Configuration/ZanoPoolConfigExtra.cs b/src/Miningcore/Blockchain/Zano/Configuration/ZanoPoolConfigExtra.cs new file mode 100644 index 0000000000..2f904bde7f --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/Configuration/ZanoPoolConfigExtra.cs @@ -0,0 +1,17 @@ +using Miningcore.Configuration; +using Newtonsoft.Json.Linq; + +namespace Miningcore.Blockchain.Zano.Configuration; + +public class ZanoPoolConfigExtra +{ + /// + /// Base directory for generated DAGs + /// + public string DagDir { get; set; } + + /// + /// Blocktemplate stream published via ZMQ + /// + public ZmqPubSubEndpointConfig BtStream { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/Configuration/ZanoPoolPaymentProcessingConfigExtra.cs b/src/Miningcore/Blockchain/Zano/Configuration/ZanoPoolPaymentProcessingConfigExtra.cs new file mode 100644 index 0000000000..f384398b6d --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/Configuration/ZanoPoolPaymentProcessingConfigExtra.cs @@ -0,0 +1,36 @@ +namespace Miningcore.Blockchain.Zano.Configuration; + +public class ZanoPoolPaymentProcessingConfigExtra +{ + public decimal MinimumPaymentToPaymentId { get; set; } + + /// + /// Reveal information about sender of this transaction, basically add sender address to transaction in encrypted way, so only receiver can see who sent transaction + /// Default: true + /// + public bool RevealPoolAddress { get; set; } + + /// + /// This add to transaction information about remote address(destination), might be needed when the wallet restored from seed phrase and fully resynched, if this option were true, then sender won't be able to see remote address for sent transactions anymore. + /// Default: False + /// + public bool HideMinerAddress { get; set; } + + /// + /// Maximum of simultaneous destination address in a single transaction + /// Default: 256 + /// + public int? MaximumDestinationPerTransfer { get; set; } + + /// + /// If True, miners pay payment tx fees + /// Default: False + /// + public bool KeepTransactionFees { get; set; } + + /// + /// Maximum amount you're willing to pay (in coin smallest unit) + /// Default: 10000000000 (0.01) + /// + public ulong? MaxFee { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/DaemonRequests/GetBlockHeaderByHashRequest.cs b/src/Miningcore/Blockchain/Zano/DaemonRequests/GetBlockHeaderByHashRequest.cs new file mode 100644 index 0000000000..111bf25da9 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/DaemonRequests/GetBlockHeaderByHashRequest.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Zano.DaemonRequests; + +public class GetBlockHeaderByHashRequest +{ + public string Hash { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/DaemonRequests/GetBlockHeaderByHeightRequest.cs b/src/Miningcore/Blockchain/Zano/DaemonRequests/GetBlockHeaderByHeightRequest.cs new file mode 100644 index 0000000000..d4a89cc3a5 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/DaemonRequests/GetBlockHeaderByHeightRequest.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Zano.DaemonRequests; + +public class GetBlockHeaderByHeightRequest +{ + public ulong Height { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/DaemonRequests/GetBlockTemplateRequest.cs b/src/Miningcore/Blockchain/Zano/DaemonRequests/GetBlockTemplateRequest.cs new file mode 100644 index 0000000000..350e5a6a9e --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/DaemonRequests/GetBlockTemplateRequest.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Zano.DaemonRequests; + +public class GetBlockTemplateRequest +{ + /// + /// Address of wallet to receive coinbase transactions if block is successfully mined. + /// + [JsonProperty("wallet_address")] + public string WalletAddress { get; set; } + + [JsonProperty("reserve_size")] + public uint ReserveSize { get; set; } + + [JsonProperty("extra_text")] + public string ExtraData { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/DaemonRequests/TransferRequest.cs b/src/Miningcore/Blockchain/Zano/DaemonRequests/TransferRequest.cs new file mode 100644 index 0000000000..77ebf4daff --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/DaemonRequests/TransferRequest.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Zano.DaemonRequests; + +public class TransferDestination +{ + public string Address { get; set; } + public ulong Amount { get; set; } + + // Salvium + /// + /// Define the type of coin to be received + /// + [JsonProperty("asset_id", NullValueHandling = NullValueHandling.Ignore)] + public string AssetType { get; set; } +} + +public class TransferRequest +{ + public TransferDestination[] Destinations { get; set; } + + /// + /// Fee to be paid on behalf of sender's wallet(paid in native coins) + /// + [JsonProperty("fee", NullValueHandling = NullValueHandling.Ignore)] + public ulong Fee { get; set; } + + /// + /// Number of outpouts from the blockchain to mix with (0 means no mixing) + /// + public uint Mixin { get; set; } + + /// + /// (Optional) Random 32-byte/64-character hex string to identify a transaction + /// + [JsonProperty("payment_id", NullValueHandling = NullValueHandling.Ignore)] + public string PaymentId { get; set; } + + /// + /// Text comment that is displayed in UI + /// + [JsonProperty("comment", NullValueHandling = NullValueHandling.Ignore)] + public string Comment { get; set; } + + /// + /// Reveal information about sender of this transaction, basically add sender address to transaction in encrypted way, so only receiver can see who sent transaction + /// + [JsonProperty("push_payer")] + public bool RevealSender { get; set; } = true; + + /// + /// This add to transaction information about remote address(destination), might be needed when the wallet restored from seed phrase and fully resynched, if this option were true, then sender won't be able to see remote address for sent transactions anymore. + /// + [JsonProperty("hide_receiver")] + public bool HideReceiver { get; set; } = false; +} diff --git a/src/Miningcore/Blockchain/Zano/DaemonResponses/GetAddressResponse.cs b/src/Miningcore/Blockchain/Zano/DaemonResponses/GetAddressResponse.cs new file mode 100644 index 0000000000..741d38bcde --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/DaemonResponses/GetAddressResponse.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Zano.DaemonResponses; + +public class GetAddressResponse +{ + public string Address { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/DaemonResponses/GetBalanceResponse.cs b/src/Miningcore/Blockchain/Zano/DaemonResponses/GetBalanceResponse.cs new file mode 100644 index 0000000000..79916bc5f8 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/DaemonResponses/GetBalanceResponse.cs @@ -0,0 +1,36 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Zano.DaemonResponses; + +public class GetBalanceResponse +{ + public decimal Balance { get; set; } + + [JsonProperty("unlocked_balance")] + public decimal UnlockedBalance { get; set; } + + public BalanceAsset[] Balances { get; set; } +} + +public class BalanceAsset +{ + [JsonProperty("asset_info")] + public BalanceAssetInfo Asset { get; set; } + + [JsonProperty("total")] + public decimal Balance { get; set; } + + [JsonProperty("unlocked")] + public decimal UnlockedBalance { get; set; } +} + +public class BalanceAssetInfo +{ + [JsonProperty("asset_id")] + public string Id { get; set; } + + [JsonProperty("full_name")] + public string Name { get; set; } + + public string Ticker { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/DaemonResponses/GetBlockHeaderResponse.cs b/src/Miningcore/Blockchain/Zano/DaemonResponses/GetBlockHeaderResponse.cs new file mode 100644 index 0000000000..03730ee554 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/DaemonResponses/GetBlockHeaderResponse.cs @@ -0,0 +1,34 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Zano.DaemonResponses; + +public class BlockHeader +{ + public long Difficulty { get; set; } + public long Depth { get; set; } + public uint Height { get; set; } + public string Hash { get; set; } + public string Nonce { get; set; } + public ulong Reward { get; set; } + public ulong Timestamp { get; set; } + + [JsonProperty("major_version")] + public uint MajorVersion { get; set; } + + [JsonProperty("minor_version")] + public uint MinorVersion { get; set; } + + [JsonProperty("prev_hash")] + public string PreviousBlockhash { get; set; } + + [JsonProperty("orphan_status")] + public bool IsOrphaned { get; set; } +} + +public class GetBlockHeaderResponse +{ + [JsonProperty("block_header")] + public BlockHeader BlockHeader { get; set; } + + public string Status { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/DaemonResponses/GetBlockTemplateResponse.cs b/src/Miningcore/Blockchain/Zano/DaemonResponses/GetBlockTemplateResponse.cs new file mode 100644 index 0000000000..f6b3d3bd82 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/DaemonResponses/GetBlockTemplateResponse.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Zano.DaemonResponses; + +public class GetBlockTemplateResponse +{ + [JsonProperty("blocktemplate_blob")] + public string Blob { get; set; } + + public long Difficulty { get; set; } + public uint Height { get; set; } + + [JsonProperty("prev_hash")] + public string PreviousBlockhash { get; set; } + + [JsonProperty("seed")] + public string SeedHash { get; set; } + + [JsonProperty("reserved_offset")] + public int? ReservedOffset { get; set; } + + public string Status { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/DaemonResponses/GetInfoResponse.cs b/src/Miningcore/Blockchain/Zano/DaemonResponses/GetInfoResponse.cs new file mode 100644 index 0000000000..98432c70da --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/DaemonResponses/GetInfoResponse.cs @@ -0,0 +1,93 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Zano.DaemonResponses; + +public class GetInfoResponse +{ + /// + /// Current target for next proof of work. + /// + public uint Target { get; set; } + + /// + /// The height of the next block in the chain. + /// + [JsonProperty("target_height")] + public uint TargetHeight { get; set; } + + /// + /// States if the node is on the testnet(true) or mainnet(false). + /// + [JsonProperty("testnet")] + public bool IsTestnet { get; set; } + + /// + /// States if the node is on the testnet(true) or mainnet(false). + /// + [JsonProperty("nettype")] + public string NetType { get; set; } = "mainnet"; + + /// + /// Hash of the highest block in the chain. + /// + [JsonProperty("top_block_hash")] + public string TopBlockHash { get; set; } + + /// + /// Total number of non-coinbase transaction in the chain. + /// + [JsonProperty("tx_count")] + public uint TransactionCount { get; set; } + + /// + /// Number of transactions that have been broadcast but not included in a block. + /// + [JsonProperty("tx_pool_size")] + public uint TransactionPoolSize { get; set; } + + /// + /// Network difficulty(analogous to the strength of the network) + /// + [JsonProperty("pow_difficulty")] + public ulong Difficulty { get; set; } + + /// + /// Current length of longest chain known to daemon. + /// + public uint Height { get; set; } + + /// + /// General RPC error code. "OK" means everything looks good. + /// + public string Status { get; set; } + + /// + /// Number of alternative blocks to main chain. + /// + [JsonProperty("alt_blocks_count")] + public int AltBlocksCount { get; set; } + + /// + /// Grey Peerlist Size + /// + [JsonProperty("grey_peerlist_size")] + public int GreyPeerlistSize { get; set; } + + /// + /// White Peerlist Size + /// + [JsonProperty("white_peerlist_size")] + public uint WhitePeerlistSize { get; set; } + + /// + /// Number of peers connected to and pulling from your node. + /// + [JsonProperty("incoming_connections_count")] + public int IncomingConnectionsCount { get; set; } + + /// + /// Number of peers that you are connected to and getting information from. + /// + [JsonProperty("outgoing_connections_count")] + public int OutgoingConnectionsCount { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/DaemonResponses/SplitIntegratedAddressResponse.cs b/src/Miningcore/Blockchain/Zano/DaemonResponses/SplitIntegratedAddressResponse.cs new file mode 100644 index 0000000000..fc522891da --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/DaemonResponses/SplitIntegratedAddressResponse.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Zano.DaemonResponses; + +public class SplitIntegratedAddressResponse +{ + [JsonProperty("standard_address")] + public string StandardAddress { get; set; } + + /// + /// Hex-encoded payment id + /// + [JsonProperty("payment_id")] + public string Payment { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/DaemonResponses/SubmitResponse.cs b/src/Miningcore/Blockchain/Zano/DaemonResponses/SubmitResponse.cs new file mode 100644 index 0000000000..733576c167 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/DaemonResponses/SubmitResponse.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Zano.DaemonResponses; + +public class SubmitResponse +{ + public string Status { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/DaemonResponses/TransferResponse.cs b/src/Miningcore/Blockchain/Zano/DaemonResponses/TransferResponse.cs new file mode 100644 index 0000000000..82b44f07e2 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/DaemonResponses/TransferResponse.cs @@ -0,0 +1,24 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Zano.DaemonResponses; + +public class TransferResponse +{ + /// + /// Publically searchable transaction hash + /// + [JsonProperty("tx_hash")] + public string TxHash { get; set; } + + /// + /// Raw transaction represented as hex string. For cold-signing process + /// + [JsonProperty("tx_unsigned_hex")] + public string TxUnsignedHex { get; set; } + + /// + /// Transaction size in bytes + /// + [JsonProperty("tx_size")] + public string TxSize { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/DaemonResponses/TransferSplitResponse.cs b/src/Miningcore/Blockchain/Zano/DaemonResponses/TransferSplitResponse.cs new file mode 100644 index 0000000000..1b05b7d362 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/DaemonResponses/TransferSplitResponse.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Zano.DaemonResponses; + +public class TransferSplitResponse +{ + /// + /// List of tx fees charged for the txn (piconeros) + /// + [JsonProperty("fee_list")] + public ulong[] FeeList { get; set; } + + /// + /// Publically searchable transaction hash + /// + [JsonProperty("tx_hash_list")] + public string[] TxHashList { get; set; } + + public string Status { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/StratumRequests/ZanoGetJobRequest.cs b/src/Miningcore/Blockchain/Zano/StratumRequests/ZanoGetJobRequest.cs new file mode 100644 index 0000000000..df87a29007 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/StratumRequests/ZanoGetJobRequest.cs @@ -0,0 +1,9 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Zano.StratumRequests; + +public class ZanoGetJobRequest +{ + [JsonProperty("id")] + public string WorkerId { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/StratumRequests/ZanoLoginRequest.cs b/src/Miningcore/Blockchain/Zano/StratumRequests/ZanoLoginRequest.cs new file mode 100644 index 0000000000..d83c525127 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/StratumRequests/ZanoLoginRequest.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Zano.StratumRequests; + +public class ZanoLoginRequest +{ + [JsonProperty("login")] + public string Login { get; set; } + + [JsonProperty("pass")] + public string Password { get; set; } + + [JsonProperty("agent")] + public string UserAgent { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/StratumRequests/ZanoSubmitShareRequest.cs b/src/Miningcore/Blockchain/Zano/StratumRequests/ZanoSubmitShareRequest.cs new file mode 100644 index 0000000000..6d9a4dc4ed --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/StratumRequests/ZanoSubmitShareRequest.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Zano.StratumRequests; + +public class ZanoSubmitShareRequest +{ + [JsonProperty("job_id")] + public string JobId { get; set; } + + public string Nonce { get; set; } + + [JsonProperty("result")] + public string Hash { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/StratumResponses/ZanoKeepAliveResponse.cs b/src/Miningcore/Blockchain/Zano/StratumResponses/ZanoKeepAliveResponse.cs new file mode 100644 index 0000000000..8bfba6cd94 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/StratumResponses/ZanoKeepAliveResponse.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Zano.StratumResponses; + +public class ZanoKeepAliveResponse +{ + public string Status { get; set; } = "KEEPALIVED"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Zano/StratumResponses/ZanoLoginResponse.cs b/src/Miningcore/Blockchain/Zano/StratumResponses/ZanoLoginResponse.cs new file mode 100644 index 0000000000..a9d5af7d05 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/StratumResponses/ZanoLoginResponse.cs @@ -0,0 +1,29 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Zano.StratumResponses; + +public class ZanoJobParams +{ + [JsonProperty("job_id")] + public string JobId { get; set; } + + public string Blob { get; set; } + public string Target { get; set; } + + [JsonProperty("seed_hash")] + public string SeedHash { get; set; } + + [JsonProperty("algo")] + public string Algorithm { get; set; } + + /// + /// Introduced for CNv4 (aka CryptonightR) + /// + public ulong Height { get; set; } +} + +public class ZanoLoginResponse : ZanoResponseBase +{ + public string Id { get; set; } + public ZanoJobParams Job { get; set; } +} diff --git a/src/Miningcore/Blockchain/Zano/StratumResponses/ZanoResponseBase.cs b/src/Miningcore/Blockchain/Zano/StratumResponses/ZanoResponseBase.cs new file mode 100644 index 0000000000..3b18ca9bc0 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/StratumResponses/ZanoResponseBase.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Zano.StratumResponses; + +public class ZanoResponseBase +{ + public string Status { get; set; } = "OK"; +} diff --git a/src/Miningcore/Blockchain/Zano/ZanoConstants.cs b/src/Miningcore/Blockchain/Zano/ZanoConstants.cs new file mode 100644 index 0000000000..387da48969 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/ZanoConstants.cs @@ -0,0 +1,80 @@ +using System.Globalization; +using System.Text.RegularExpressions; +using Org.BouncyCastle.Math; + +namespace Miningcore.Blockchain.Zano; + +public enum ZanoNetworkType +{ + Main = 1, + Test +} + +public static class ZanoConstants +{ + public const int EpochLength = 30000; + + public const string WalletDaemonCategory = "wallet"; + + public const string DaemonRpcLocation = "json_rpc"; + public const int RpcMethodNotFound = -32601; + public const int PaymentIdHexLength = 64; + public static readonly Regex RegexValidNonce = new("^[0-9a-f]{16}$", RegexOptions.Compiled); + + public static readonly BigInteger Diff1 = new("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16); + public static readonly System.Numerics.BigInteger Diff1b = System.Numerics.BigInteger.Parse("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", NumberStyles.HexNumber); + public static double DifficultyPowTarget = 120.0d; + +#if DEBUG + public const int PayoutMinBlockConfirmations = 2; +#else + public const int PayoutMinBlockConfirmations = 60; +#endif + + public const int InstanceIdSize = 4; + public const int ExtraNonceSize = 4; + + public const int BlockTemplateReservedOffset = 1; + public const int BlockTemplateInstanceIdOffset = 8; + public const int BlockTemplateExtraNonceOffset = 12; + + public const int EncodeBlobSize = 32; + public const int TargetPaddingLength = 32; + + // NOTE: for whatever strange reason only reserved_size -1 can be used, + // the LAST byte MUST be zero or nothing works + public const int ReserveSize = ExtraNonceSize + InstanceIdSize + 1; + + // Offset to prevHash in block blob + public const int BlobPrevHashOffset = 9; + + // Offset to nonce in block blob + public const int BlobNonceOffset = 39; + + public const ulong MinimumTransactionFee = 10000000000; // in zano smallest unit +} + +public static class ZanoCommands +{ + // https://github.com/hyle-team/zano/blob/master/src/rpc/core_rpc_server.h + // https://github.com/hyle-team/zano/blob/master/src/rpc/core_rpc_server_commands_defs.h + public const string GetInfo = "getinfo"; + public const string GetBlockTemplate = "getblocktemplate"; + public const string SubmitBlock = "submitblock"; + public const string GetBlockHeaderByHash = "getblockheaderbyhash"; + public const string GetBlockHeaderByHeight = "getblockheaderbyheight"; +} + +public static class ZanoWalletCommands +{ + // https://github.com/hyle-team/zano/blob/master/src/wallet/wallet_rpc_server.h + // https://github.com/hyle-team/zano/blob/master/src/rpc/core_rpc_server_commands_defs.h + + public const string GetBalance = "getbalance"; + public const string GetAddress = "getaddress"; + public const string Transfer = "transfer"; + public const string TransferSplit = "transfer_split"; + public const string GetTransfers = "get_payments"; + public const string SplitIntegratedAddress = "split_integrated_address"; + public const string Store = "store"; +} diff --git a/src/Miningcore/Blockchain/Zano/ZanoJob.cs b/src/Miningcore/Blockchain/Zano/ZanoJob.cs new file mode 100644 index 0000000000..ddcd15a47f --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/ZanoJob.cs @@ -0,0 +1,180 @@ +using System.Globalization; +using Miningcore.Blockchain.Zano.DaemonResponses; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.Native; +using Miningcore.Stratum; +using Miningcore.Util; +using Org.BouncyCastle.Math; +using Miningcore.Crypto.Hashing.Progpow; +using NLog; +using Contract = Miningcore.Contracts.Contract; + +namespace Miningcore.Blockchain.Zano; + +public class ZanoJob +{ + public ZanoJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, + ZanoCoinTemplate coin, PoolConfig poolConfig, ClusterConfig clusterConfig, string prevHash, IProgpowCache progpowHasher) + { + Contract.RequiresNonNull(blockTemplate); + Contract.RequiresNonNull(poolConfig); + Contract.RequiresNonNull(clusterConfig); + Contract.RequiresNonNull(instanceId); + Contract.RequiresNonNull(progpowHasher); + + BlockTemplate = blockTemplate; + PrepareBlobTemplate(instanceId); + PrevHash = prevHash; + ReservedOffset = BlockTemplate?.ReservedOffset ?? ZanoConstants.BlockTemplateReservedOffset; + this.progpowHasher = progpowHasher; + + Span heightBytes = stackalloc byte[8]; + // inject height (big-endian) at the end of the reserved area + var bytes = BitConverter.GetBytes(BlockTemplate.Height.ToBigEndian()); + bytes.CopyTo(heightBytes[4..]); + + Height = heightBytes.ToHexString(true); + shareMultiplier = coin.ShareMultiplier; + + blobType = coin.BlobType; + } + + protected double shareMultiplier; + protected IProgpowCache progpowHasher; + + private int ReservedOffset; + private byte[] blobTemplate; + private byte[] instanceId; + private int extraNonce; + private readonly int blobType; + + protected virtual void PrepareBlobTemplate(byte[] instanceId) + { + this.instanceId = instanceId; + blobTemplate = BlockTemplate.Blob.HexToByteArray(); + } + + protected virtual byte[] EncodeBlob(uint workerExtraNonce) + { + byte[] blobHash = new byte[ZanoConstants.EncodeBlobSize]; + // hash it + ZanonoteBindings.GetBlobId(blobTemplate, blobHash); + + return blobHash; + } + + protected virtual string EncodeTarget(double difficulty, int size = 32) + { + var diff = BigInteger.ValueOf((long) (difficulty * 255d)); + var quotient = ZanoConstants.Diff1.Divide(diff).Multiply(BigInteger.ValueOf(255)); + var bytes = quotient.ToByteArray().AsSpan(); + Span padded = stackalloc byte[ZanoConstants.TargetPaddingLength]; + + var padLength = padded.Length - bytes.Length; + + if(padLength > 0) + bytes.CopyTo(padded.Slice(padLength, bytes.Length)); + else + bytes.Slice(bytes.Length - padded.Length, padded.Length).CopyTo(padded); + + padded = padded[..size]; + + return padded.ToHexString(true); + } + + #region API-Surface + + public string PrevHash { get; } + public GetBlockTemplateResponse BlockTemplate { get; } + public string Height { get; protected set; } + + public virtual ZanoWorkerJob PrepareWorkerJob(double difficulty) + { + var workerExtraNonce = (uint) Interlocked.Increment(ref extraNonce); + + if(extraNonce < 0) + extraNonce = 0; + + var workerJob = new ZanoWorkerJob(EncodeBlob(workerExtraNonce).ToHexString(true), difficulty); + workerJob.Height = Height; + workerJob.ExtraNonce = workerExtraNonce; + workerJob.SeedHash = BlockTemplate.SeedHash.HexToByteArray().ToHexString(true); + workerJob.Target = EncodeTarget(workerJob.Difficulty); + + return workerJob; + } + + public virtual (Share Share, string BlobHex) ProcessShare(ILogger logger, string nonce, uint workerExtraNonce, StratumConnection worker) + { + Contract.Requires(!string.IsNullOrEmpty(nonce)); + Contract.Requires(workerExtraNonce != 0); + + var context = worker.ContextAs(); + + // validate nonce + if(!ZanoConstants.RegexValidNonce.IsMatch(nonce)) + throw new StratumException(StratumError.MinusOne, "malformed nonce"); + + if(!ulong.TryParse(nonce, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var fullNonce)) + throw new StratumException(StratumError.MinusOne, "bad nonce " + nonce); + + var blobBytes = ZanonoteBindings.ConvertBlock(blobTemplate, blobTemplate.Length, fullNonce); + + // compute + if(!progpowHasher.Compute(logger, (int) BlockTemplate.Height, EncodeBlob(workerExtraNonce), fullNonce, out var _, out var resultBytes)) + throw new StratumException(StratumError.MinusOne, "bad hash"); + + resultBytes.ReverseInPlace(); + //throw new StratumException(StratumError.LowDifficultyShare, $"nonce: {nonce} ||| Height: {(int) BlockTemplate.Height} ||| blobBytes: {blobBytes.ToHexString()} ||| resultBytes: {resultBytes.ToHexString()} ||| headerValue: {resultBytes.AsSpan().ToBigInteger()} ||| shareDiff: {(double) new BigRational(ZanoConstants.Diff1b, resultBytes.AsSpan().ToBigInteger()) * shareMultiplier} [isBlockCandidate: {(((double) new BigRational(ZanoConstants.Diff1b, resultBytes.AsSpan().ToBigInteger()) * shareMultiplier) >= BlockTemplate.Difficulty)} - isStratumCandidate: {(((double) new BigRational(ZanoConstants.Diff1b, resultBytes.AsSpan().ToBigInteger()) * shareMultiplier) >= context.Difficulty)} - stratum: {context.Difficulty} - blockTemplate: {BlockTemplate.Difficulty}]"); + + // check difficulty + var headerValue = resultBytes.AsSpan().ToBigInteger(); + var shareDiff = (double) new BigRational(ZanoConstants.Diff1b, headerValue) * shareMultiplier; + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; + var isBlockCandidate = shareDiff >= BlockTemplate.Difficulty; + + // test if share meets at least workers current difficulty + 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) + { + ratio = shareDiff / context.PreviousDifficulty.Value; + + if(ratio < 0.99) + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + + // use previous difficulty + stratumDifficulty = context.PreviousDifficulty.Value; + } + + else + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + } + + var result = new Share + { + BlockHeight = BlockTemplate.Height, + Difficulty = stratumDifficulty / shareMultiplier, + }; + + if(isBlockCandidate) + { + byte[] blockHash = new byte[32]; + // compute blob hash + ZanonoteBindings.GetBlockId(blobBytes, blockHash); + + // Fill in block-relevant fields + result.IsBlockCandidate = true; + result.BlockHash = blockHash.ToHexString(); + + return (result, blobBytes.ToHexString()); + } + + return (result, null); + } + + #endregion // API-Surface +} diff --git a/src/Miningcore/Blockchain/Zano/ZanoJobManager.cs b/src/Miningcore/Blockchain/Zano/ZanoJobManager.cs new file mode 100644 index 0000000000..1639d674ab --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/ZanoJobManager.cs @@ -0,0 +1,648 @@ +using System.Globalization; +using System.Reactive; +using System.Reactive.Linq; +using System.Security.Cryptography; +using System.Text; +using Autofac; +using Miningcore.Blockchain.Bitcoin; +using Miningcore.Blockchain.Zano.Configuration; +using Miningcore.Blockchain.Zano.DaemonRequests; +using Miningcore.Blockchain.Zano.DaemonResponses; +using Miningcore.Blockchain.Zano.StratumRequests; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.JsonRpc; +using Miningcore.Messaging; +using Miningcore.Mining; +using Miningcore.Native; +using Miningcore.Notifications.Messages; +using Miningcore.Rpc; +using Miningcore.Stratum; +using Miningcore.Time; +using Miningcore.Util; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NLog; +using Contract = Miningcore.Contracts.Contract; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Zano; + +public class ZanoJobManager : JobManagerBase +{ + public ZanoJobManager( + IComponentContext ctx, + IMasterClock clock, + IMessageBus messageBus) : + base(ctx, messageBus) + { + Contract.RequiresNonNull(ctx); + Contract.RequiresNonNull(clock); + Contract.RequiresNonNull(messageBus); + + this.clock = clock; + } + + private byte[] instanceId; + private DaemonEndpointConfig[] daemonEndpoints; + private RpcClient rpc; + private RpcClient walletRpc; + private readonly IMasterClock clock; + private ZanoNetworkType networkType; + private ZanoPoolConfigExtra extraPoolConfig; + private ulong poolAddressBase58Prefix; + private DaemonEndpointConfig[] walletDaemonEndpoints; + private ZanoCoinTemplate coin; + + protected async Task UpdateJob(CancellationToken ct, string via = null, string json = null) + { + try + { + var response = string.IsNullOrEmpty(json) ? await GetBlockTemplateAsync(ct) : GetBlockTemplateFromJson(json); + + // may happen if daemon is currently not connected to peers + if(response.Error != null) + { + logger.Warn(() => $"Unable to update job. Daemon responded with: {response.Error.Message} Code {response.Error.Code}"); + return false; + } + + var blockTemplate = response.Response; + var job = currentJob; + var newHash = blockTemplate.Blob.HexToByteArray().AsSpan().Slice(ZanoConstants.BlobPrevHashOffset, 32).ToHexString(); + + var isNew = job == null || + (job.BlockTemplate?.Height < blockTemplate.Height && newHash != job.PrevHash); + + if(isNew) + { + messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); + + if(via != null) + logger.Info(() => $"Detected new block {blockTemplate.Height} [{via}]"); + else + logger.Info(() => $"Detected new block {blockTemplate.Height}"); + + var progpowHasher = await coin.ProgpowHasher.GetCacheAsync(logger, (int) blockTemplate.Height, ct); + + // init job + job = new ZanoJob(blockTemplate, instanceId, coin, poolConfig, clusterConfig, newHash, progpowHasher); + currentJob = job; + + // update stats + BlockchainStats.LastNetworkBlockTime = clock.Now; + BlockchainStats.BlockHeight = job.BlockTemplate.Height; + BlockchainStats.NetworkDifficulty = job.BlockTemplate.Difficulty; + BlockchainStats.NextNetworkTarget = ""; + BlockchainStats.NextNetworkBits = ""; + } + + else + { + if(via != null) + logger.Debug(() => $"Template update {blockTemplate.Height} [{via}]"); + else + logger.Debug(() => $"Template update {blockTemplate.Height}"); + } + + return isNew; + } + + catch(OperationCanceledException) + { + // ignored + } + + catch(Exception ex) + { + logger.Error(ex, () => $"Error during {nameof(UpdateJob)}"); + } + + return false; + } + + private async Task> GetBlockTemplateAsync(CancellationToken ct) + { + var request = new GetBlockTemplateRequest + { + WalletAddress = poolConfig.Address, + ReserveSize = ZanoConstants.ReserveSize + }; + + return await rpc.ExecuteAsync(logger, ZanoCommands.GetBlockTemplate, ct, request); + } + + private RpcResponse GetBlockTemplateFromJson(string json) + { + var result = JsonConvert.DeserializeObject(json); + + return new RpcResponse(result.ResultAs()); + } + + private async Task ShowDaemonSyncProgressAsync(CancellationToken ct) + { + var response = await rpc.ExecuteAsync(logger, ZanoCommands.GetInfo, ct); + var info = response.Response; + + if(info != null) + { + var lowestHeight = info.Height; + + var totalBlocks = info.TargetHeight; + var percent = (double) lowestHeight / totalBlocks * 100; + + logger.Info(() => $"Daemon has downloaded {percent:0.00}% of blockchain from {info.OutgoingConnectionsCount} peers"); + } + } + + private async Task UpdateNetworkStatsAsync(CancellationToken ct) + { + try + { + var response = await rpc.ExecuteAsync(logger, ZanoCommands.GetInfo, ct); + + if(response.Error != null) + logger.Warn(() => $"Error(s) refreshing network stats: {response.Error.Message} (Code {response.Error.Code})"); + + if(response.Response != null) + { + var info = response.Response.ToObject(); + + BlockchainStats.NetworkHashrate = info.Difficulty / ZanoConstants.DifficultyPowTarget; + BlockchainStats.ConnectedPeers = info.OutgoingConnectionsCount + info.IncomingConnectionsCount; + } + } + + catch(Exception e) + { + logger.Error(e); + } + } + + private async Task SubmitBlockAsync(Share share, string blobHex, string blobHash) + { + var response = await rpc.ExecuteAsync(logger, ZanoCommands.SubmitBlock, CancellationToken.None, new[] { blobHex }); + + if(response.Error != null || response?.Response?.Status != "OK") + { + var error = response.Error?.Message ?? response.Response?.Status; + + logger.Warn(() => $"Block {share.BlockHeight} [{blobHash[..6]}] submission failed with: {error}"); + 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}: {error}")); + return false; + } + + return true; + } + + public ZanoWorkerJob PrepareWorkerJob(double difficulty) + { + var job = currentJob; + return job.PrepareWorkerJob(difficulty); + } + + public override ZanoJob GetJobForStratum() + { + var job = currentJob; + return job; + } + + #region API-Surface + + public IObservable Blocks { get; private set; } + + public ZanoCoinTemplate Coin => coin; + + public override void Configure(PoolConfig pc, ClusterConfig cc) + { + Contract.RequiresNonNull(pc); + Contract.RequiresNonNull(cc); + + logger = LogUtil.GetPoolScopedLogger(typeof(JobManagerBase), pc); + poolConfig = pc; + clusterConfig = cc; + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); + coin = pc.Template.As(); + + // extract standard daemon endpoints + daemonEndpoints = pc.Daemons + .Where(x => string.IsNullOrEmpty(x.Category)) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = ZanoConstants.DaemonRpcLocation; + + return x; + }) + .ToArray(); + + if(cc.PaymentProcessing?.Enabled == true && pc.PaymentProcessing?.Enabled == true) + { + // extract wallet daemon endpoints + walletDaemonEndpoints = pc.Daemons + .Where(x => x.Category?.ToLower() == ZanoConstants.WalletDaemonCategory) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = ZanoConstants.DaemonRpcLocation; + + return x; + }) + .ToArray(); + + if(walletDaemonEndpoints.Length == 0) + throw new PoolStartupException("Wallet-RPC daemon is not configured (Daemon configuration for monero-pools require an additional entry of category \'wallet' pointing to the wallet daemon)", pc.Id); + } + + ConfigureDaemons(); + } + + public bool ValidateAddress(string address) + { + if(string.IsNullOrEmpty(address)) + return false; + + var addressPrefix = CryptonoteBindings.DecodeAddress(address); + var addressIntegratedPrefix = CryptonoteBindings.DecodeIntegratedAddress(address); + var coin = poolConfig.Template.As(); + + switch(networkType) + { + case ZanoNetworkType.Main: + if(addressPrefix != coin.AddressPrefix && + addressPrefix != coin.AuditableAddressPrefix && + addressIntegratedPrefix != coin.AddressPrefixIntegrated && + addressIntegratedPrefix != coin.AddressV2PrefixIntegrated && + addressIntegratedPrefix != coin.AuditableAddressIntegratedPrefix) + return false; + break; + + case ZanoNetworkType.Test: + if(addressPrefix != coin.AddressPrefixTestnet && + addressPrefix != coin.AuditableAddressPrefixTestnet && + addressIntegratedPrefix != coin.AddressPrefixIntegratedTestnet && + addressIntegratedPrefix != coin.AddressV2PrefixIntegratedTestnet && + addressIntegratedPrefix != coin.AuditableAddressIntegratedPrefixTestnet) + return false; + break; + } + + return true; + } + + public BlockchainStats BlockchainStats { get; } = new(); + + public async ValueTask SubmitShareAsync(StratumConnection worker, + ZanoSubmitShareRequest request, ZanoWorkerJob workerJob, CancellationToken ct) + { + Contract.RequiresNonNull(worker); + Contract.RequiresNonNull(request); + + var context = worker.ContextAs(); + + var job = currentJob; + if(workerJob.Height != job?.Height) + throw new StratumException(StratumError.MinusOne, "block expired"); + + // validate & process + var (share, blobHex) = job.ProcessShare(logger, request.Nonce, workerJob.ExtraNonce, worker); + + // enrich share with common data + share.PoolId = poolConfig.Id; + share.IpAddress = worker.RemoteEndpoint.Address.ToString(); + share.Miner = context.Miner; + share.Worker = context.Worker; + share.UserAgent = context.UserAgent; + share.Source = clusterConfig.ClusterName; + share.NetworkDifficulty = job.BlockTemplate.Difficulty; + share.Created = clock.Now; + + // if block candidate, submit & check if accepted by network + if(share.IsBlockCandidate) + { + logger.Info(() => $"Submitting block {share.BlockHeight} [{share.BlockHash[..6]}]"); + + share.IsBlockCandidate = await SubmitBlockAsync(share, blobHex, share.BlockHash); + + if(share.IsBlockCandidate) + { + logger.Info(() => $"Daemon accepted block {share.BlockHeight} [{share.BlockHash[..6]}] submitted by {context.Miner}"); + + OnBlockFound(); + + share.TransactionConfirmationData = share.BlockHash; + } + + else + { + // clear fields that no longer apply + share.TransactionConfirmationData = null; + } + } + + return share; + } + + #endregion // API-Surface + + private static JToken GetFrameAsJToken(byte[] frame) + { + var text = Encoding.UTF8.GetString(frame); + + // find end of message type indicator + var index = text.IndexOf(":"); + + if (index == -1) + return null; + + var json = text.Substring(index + 1); + + return JToken.Parse(json); + } + + #region Overrides + + protected override void ConfigureDaemons() + { + var jsonSerializerSettings = ctx.Resolve(); + + rpc = new RpcClient(daemonEndpoints.First(), jsonSerializerSettings, messageBus, poolConfig.Id); + + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + // also setup wallet daemon + walletRpc = new RpcClient(walletDaemonEndpoints.First(), jsonSerializerSettings, messageBus, poolConfig.Id); + } + } + + protected override async Task AreDaemonsHealthyAsync(CancellationToken ct) + { + // test daemons + var response = await rpc.ExecuteAsync(logger, ZanoCommands.GetInfo, ct); + + if(response.Error != null) + return false; + + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + // test wallet daemons + var responses2 = await walletRpc.ExecuteAsync(logger, ZanoWalletCommands.GetAddress, ct); + + return responses2.Error == null; + } + + return true; + } + + protected override async Task AreDaemonsConnectedAsync(CancellationToken ct) + { + var response = await rpc.ExecuteAsync(logger, ZanoCommands.GetInfo, ct); + + return response.Error == null && response.Response != null && + (response.Response.OutgoingConnectionsCount + response.Response.IncomingConnectionsCount) > 0; + } + + protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) + { + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(5)); + + var syncPendingNotificationShown = false; + + do + { + var request = new GetBlockTemplateRequest + { + WalletAddress = poolConfig.Address, + ReserveSize = ZanoConstants.ReserveSize + }; + + var response = await rpc.ExecuteAsync(logger, + ZanoCommands.GetBlockTemplate, ct, request); + + var isSynched = response.Error is not {Code: -9}; + + if(isSynched) + { + logger.Info(() => "All daemons synched with blockchain"); + break; + } + + if(!syncPendingNotificationShown) + { + logger.Info(() => "Daemon is still syncing with network. Manager will be started once synced."); + syncPendingNotificationShown = true; + } + + await ShowDaemonSyncProgressAsync(ct); + } while(await timer.WaitForNextTickAsync(ct)); + } + + protected override async Task PostStartInitAsync(CancellationToken ct) + { + SetInstanceId(); + + // coin config + var coin = poolConfig.Template.As(); + var infoResponse = await rpc.ExecuteAsync(logger, ZanoCommands.GetInfo, ct); + + if(infoResponse.Error != null) + throw new PoolStartupException($"Init RPC failed: {infoResponse.Error.Message} (Code {infoResponse.Error.Code})", poolConfig.Id); + + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + var addressResponse = await walletRpc.ExecuteAsync(logger, ZanoWalletCommands.GetAddress, ct); + + // ensure pool owns wallet + if(clusterConfig.PaymentProcessing?.Enabled == true && addressResponse.Response?.Address != poolConfig.Address) + throw new PoolStartupException($"Wallet-Daemon does not own pool-address '{poolConfig.Address}'", poolConfig.Id); + } + + var info = infoResponse.Response.ToObject(); + + // chain detection + if(!string.IsNullOrEmpty(info.NetType)) + { + switch(info.NetType.ToLower()) + { + case "mainnet": + networkType = ZanoNetworkType.Main; + break; + case "testnet": + networkType = ZanoNetworkType.Test; + break; + default: + throw new PoolStartupException($"Unsupport net type '{info.NetType}'", poolConfig.Id); + } + } + + else + networkType = info.IsTestnet ? ZanoNetworkType.Test : ZanoNetworkType.Main; + + // address validation + poolAddressBase58Prefix = CryptonoteBindings.DecodeAddress(poolConfig.Address); + if(poolAddressBase58Prefix == 0) + throw new PoolStartupException("Unable to decode pool-address", poolConfig.Id); + + switch(networkType) + { + case ZanoNetworkType.Main: + if(poolAddressBase58Prefix != coin.AddressPrefix && poolAddressBase58Prefix != coin.AuditableAddressPrefix) + throw new PoolStartupException($"Invalid pool address prefix. Expected {coin.AddressPrefix} or {coin.AuditableAddressPrefix}, got {poolAddressBase58Prefix}", poolConfig.Id); + break; + + case ZanoNetworkType.Test: + if(poolAddressBase58Prefix != coin.AddressPrefixTestnet && poolAddressBase58Prefix != coin.AuditableAddressPrefixTestnet) + throw new PoolStartupException($"Invalid pool address prefix. Expected {coin.AddressPrefixTestnet} or {coin.AuditableAddressPrefixTestnet}, got {poolAddressBase58Prefix}", poolConfig.Id); + break; + } + + // update stats + BlockchainStats.RewardType = "POW"; + BlockchainStats.NetworkType = networkType.ToString(); + + await UpdateNetworkStatsAsync(ct); + + // Periodically update network stats + Observable.Interval(TimeSpan.FromMinutes(1)) + .Select(via => Observable.FromAsync(() => + Guard(()=> UpdateNetworkStatsAsync(ct), + ex=> logger.Error(ex)))) + .Concat() + .Subscribe(); + + if(poolConfig.EnableInternalStratum == true) + { + // make sure we have a current light cache + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(5)); + + do + { + var blockTemplate = await GetBlockTemplateAsync(ct); + + if(blockTemplate?.Response != null) + { + logger.Info(() => "Loading current light cache ..."); + + await coin.ProgpowHasher.GetCacheAsync(logger, (int) blockTemplate.Response.Height, ct); + + logger.Info(() => "Loaded current light cache"); + break; + } + + logger.Info(() => "Waiting for first valid block template"); + } while(await timer.WaitForNextTickAsync(ct)); + } + + SetupJobUpdates(ct); + } + + private void SetInstanceId() + { + instanceId = new byte[ZanoConstants.InstanceIdSize]; + + using(var rng = RandomNumberGenerator.Create()) + { + rng.GetNonZeroBytes(instanceId); + } + + if(clusterConfig.InstanceId.HasValue) + instanceId[0] = clusterConfig.InstanceId.Value; + } + + protected virtual void SetupJobUpdates(CancellationToken ct) + { + var blockSubmission = blockFoundSubject.Synchronize(); + var pollTimerRestart = blockFoundSubject.Synchronize(); + + var triggers = new List> + { + blockSubmission.Select(x => (JobRefreshBy.BlockFound, (string) null)) + }; + + if(extraPoolConfig?.BtStream == null) + { + // collect ports + var zmq = poolConfig.Daemons + .Where(x => !string.IsNullOrEmpty(x.Extra.SafeExtensionDataAs()?.ZmqBlockNotifySocket)) + .ToDictionary(x => x, x => + { + var extra = x.Extra.SafeExtensionDataAs(); + var topic = !string.IsNullOrEmpty(extra.ZmqBlockNotifyTopic.Trim()) ? extra.ZmqBlockNotifyTopic.Trim() : BitcoinConstants.ZmqPublisherTopicBlockHash; + + return (Socket: extra.ZmqBlockNotifySocket, Topic: topic); + }); + + if(zmq.Count > 0) + { + logger.Info(() => $"Subscribing to ZMQ push-updates from {string.Join(", ", zmq.Values)}"); + + var blockNotify = rpc.ZmqSubscribe(logger, ct, zmq) + .Select(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) + var result = msg[0].Read().ToHexString(); + return result; + } + }) + .DistinctUntilChanged() + .Select(_ => (JobRefreshBy.PubSub, (string) null)) + .Publish() + .RefCount(); + + pollTimerRestart = Observable.Merge( + blockSubmission, + blockNotify.Select(_ => Unit.Default)) + .Publish() + .RefCount(); + + triggers.Add(blockNotify); + } + + if(poolConfig.BlockRefreshInterval > 0) + { + // periodically update block-template + var pollingInterval = poolConfig.BlockRefreshInterval > 0 ? poolConfig.BlockRefreshInterval : 1000; + + triggers.Add(Observable.Timer(TimeSpan.FromMilliseconds(pollingInterval)) + .TakeUntil(pollTimerRestart) + .Select(_ => (JobRefreshBy.Poll, (string) null)) + .Repeat()); + } + + else + { + // get initial blocktemplate + triggers.Add(Observable.Interval(TimeSpan.FromMilliseconds(1000)) + .Select(_ => (JobRefreshBy.Initial, (string) null)) + .TakeWhile(_ => !hasInitialBlockTemplate)); + } + } + + else + { + triggers.Add(BtStreamSubscribe(extraPoolConfig.BtStream) + .Select(json => (JobRefreshBy.BlockTemplateStream, json)) + .Publish() + .RefCount()); + + // get initial blocktemplate + triggers.Add(Observable.Interval(TimeSpan.FromMilliseconds(1000)) + .Select(_ => (JobRefreshBy.Initial, (string) null)) + .TakeWhile(_ => !hasInitialBlockTemplate)); + } + + Blocks = triggers.Merge() + .Select(x => Observable.FromAsync(() => UpdateJob(ct, x.Via, x.Data))) + .Concat() + .Where(isNew => isNew) + .Do(_ => hasInitialBlockTemplate = true) + .Select(_ => Unit.Default) + .Publish() + .RefCount(); + } + + #endregion // Overrides +} diff --git a/src/Miningcore/Blockchain/Zano/ZanoPayoutHandler.cs b/src/Miningcore/Blockchain/Zano/ZanoPayoutHandler.cs new file mode 100644 index 0000000000..6e8d9bacb6 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/ZanoPayoutHandler.cs @@ -0,0 +1,619 @@ +using System.Data; +using Autofac; +using AutoMapper; +using Miningcore.Blockchain.Zano.Configuration; +using Miningcore.Blockchain.Zano.DaemonRequests; +using Miningcore.Blockchain.Zano.DaemonResponses; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Mining; +using Miningcore.Native; +using Miningcore.Payments; +using Miningcore.Persistence; +using Miningcore.Persistence.Model; +using Miningcore.Persistence.Repositories; +using Miningcore.Rpc; +using Miningcore.Time; +using Miningcore.Util; +using Newtonsoft.Json; +using Contract = Miningcore.Contracts.Contract; +using CNC = Miningcore.Blockchain.Zano.ZanoCommands; +using Newtonsoft.Json.Linq; + +namespace Miningcore.Blockchain.Zano; + +[CoinFamily(CoinFamily.Zano)] +public class ZanoPayoutHandler : PayoutHandlerBase, + IPayoutHandler +{ + public ZanoPayoutHandler( + IComponentContext ctx, + IConnectionFactory cf, + IMapper mapper, + IShareRepository shareRepo, + IBlockRepository blockRepo, + IBalanceRepository balanceRepo, + IPaymentRepository paymentRepo, + IMasterClock clock, + IMessageBus messageBus) : + base(cf, mapper, shareRepo, blockRepo, balanceRepo, paymentRepo, clock, messageBus) + { + Contract.RequiresNonNull(ctx); + Contract.RequiresNonNull(balanceRepo); + Contract.RequiresNonNull(paymentRepo); + + this.ctx = ctx; + } + + private readonly IComponentContext ctx; + private RpcClient rpcClient; + private RpcClient rpcClientWallet; + private ZanoNetworkType? networkType; + private ZanoPoolPaymentProcessingConfigExtra extraConfig; + private bool walletSupportsTransferSplit; + private bool revealPoolAddress; + private bool hideMinerAddress; + + protected override string LogCategory => "Zano Payout Handler"; + + private async Task HandleTransferResponseAsync(RpcResponse response, params Balance[] balances) + { + var coin = poolConfig.Template.As(); + + if(response.Error == null) + { + var txHash = response.Response.TxHash; + + logger.Info(() => $"[{LogCategory}] Payment transaction id: {txHash}"); + + await PersistPaymentsAsync(balances, txHash); + NotifyPayoutSuccess(poolConfig.Id, balances, new[] { txHash }, null); + return true; + } + + else + { + logger.Error(() => $"[{LogCategory}] Daemon command '{ZanoWalletCommands.Transfer}' returned error: {response.Error.Message} code {response.Error.Code}"); + + NotifyPayoutFailure(poolConfig.Id, balances, $"Daemon command '{ZanoWalletCommands.Transfer}' returned error: {response.Error.Message} code {response.Error.Code}", null); + return false; + } + } + + private async Task HandleTransferResponseAsync(RpcResponse response, params Balance[] balances) + { + var coin = poolConfig.Template.As(); + + if(response.Error == null) + { + var txHashes = response.Response.TxHashList; + + logger.Info(() => $"[{LogCategory}] Split-Payment transaction ids: {string.Join(", ", txHashes)}"); + + await PersistPaymentsAsync(balances, txHashes.First()); + NotifyPayoutSuccess(poolConfig.Id, balances, txHashes, null); + return true; + } + + else + { + logger.Error(() => $"[{LogCategory}] Daemon command '{ZanoWalletCommands.TransferSplit}' returned error: {response.Error.Message} code {response.Error.Code}"); + + NotifyPayoutFailure(poolConfig.Id, balances, $"Daemon command '{ZanoWalletCommands.TransferSplit}' returned error: {response.Error.Message} code {response.Error.Code}", null); + return false; + } + } + + private async Task UpdateNetworkTypeAsync(CancellationToken ct) + { + if(!networkType.HasValue) + { + var infoResponse = await rpcClient.ExecuteAsync(logger, CNC.GetInfo, ct, true); + var info = infoResponse.Response.ToObject(); + + if(info == null) + throw new PoolStartupException($"{LogCategory}] Unable to determine network type", poolConfig.Id); + + // chain detection + if(!string.IsNullOrEmpty(info.NetType)) + { + switch(info.NetType.ToLower()) + { + case "mainnet": + networkType = ZanoNetworkType.Main; + break; + case "testnet": + networkType = ZanoNetworkType.Test; + break; + default: + throw new PoolStartupException($"Unsupported net type '{info.NetType}'", poolConfig.Id); + } + } + + else + networkType = info.IsTestnet ? ZanoNetworkType.Test : ZanoNetworkType.Main; + } + } + + private async Task EnsureBalance(decimal requiredAmount, ZanoCoinTemplate coin, CancellationToken ct) + { + decimal unlockedBalance = 0.0m; + decimal balance = 0.0m; + + var responseBalance = await rpcClientWallet.ExecuteAsync(logger, ZanoWalletCommands.GetBalance, ct); + + if(responseBalance.Error != null) + { + logger.Error(() => $"[{LogCategory}] Daemon command '{ZanoWalletCommands.GetBalance}' returned error: {responseBalance.Error.Message} code {responseBalance.Error.Code}"); + return false; + } + + unlockedBalance = responseBalance.Response.UnlockedBalance / coin.SmallestUnit; + balance = responseBalance.Response.Balance / coin.SmallestUnit; + + if(unlockedBalance < requiredAmount) + { + logger.Info(() => $"[{LogCategory}] {FormatAmount(requiredAmount)} unlocked balance required for payment, but only have {FormatAmount(unlockedBalance)} of {FormatAmount(balance)} available yet. Will try again."); + return false; + } + + logger.Info(() => $"[{LogCategory}] Current balance is {FormatAmount(unlockedBalance)}"); + return true; + } + + private async Task PayoutBatch(Balance[] balances, CancellationToken ct) + { + var coin = poolConfig.Template.As(); + + // ensure there's enough balance + if(!await EnsureBalance(balances.Sum(x => x.Amount), coin, ct)) + return false; + + TransferRequest request; + var maxTransactionFees = (extraConfig?.MaxFee ?? ZanoConstants.MinimumTransactionFee) / coin.SmallestUnit; + + // build request + request = new TransferRequest + { + Destinations = balances + .Where(x => x.Amount > 0) + .Select(x => + { + ExtractAddressAndPaymentId(x.Address, out var address, out _); + + return new TransferDestination + { + Address = address, + Amount = (ulong) Math.Floor(x.Amount * coin.SmallestUnit) + }; + }).ToArray(), + + Fee = (extraConfig?.MaxFee ?? ZanoConstants.MinimumTransactionFee), + RevealSender = revealPoolAddress, + HideReceiver = hideMinerAddress + }; + + if(extraConfig?.KeepTransactionFees == true) + { + var page = balances + .Where(x => x.Amount > 0) + .ToArray(); + + logger.Debug(() => $"[{LogCategory}] Pool does not pay the transaction fee, so each address will have its payout deducted with [{FormatAmount(maxTransactionFees / page.Length)}]"); + + request = new TransferRequest + { + Destinations = balances + .Where(x => x.Amount > 0) + .Select(x => + { + ExtractAddressAndPaymentId(x.Address, out var address, out _); + + return new TransferDestination + { + Address = address, + Amount = (ulong) Math.Floor((x.Amount > (maxTransactionFees / page.Length) ? x.Amount - (maxTransactionFees / page.Length) : x.Amount) * coin.SmallestUnit) + }; + }).ToArray(), + + Fee = (extraConfig?.MaxFee ?? ZanoConstants.MinimumTransactionFee), + RevealSender = revealPoolAddress, + HideReceiver = hideMinerAddress + }; + } + + if(request.Destinations.Length == 0) + return true; + + logger.Info(() => $"[{LogCategory}] Paying {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 rpcClientWallet.ExecuteAsync(logger, ZanoWalletCommands.Transfer, ct, request); + + // gracefully handle error -4 (transaction would be too large. try /transfer_split) + if(transferResponse.Error?.Code == -4) + { + if(walletSupportsTransferSplit) + { + logger.Error(() => $"[{LogCategory}] Daemon command '{ZanoWalletCommands.Transfer}' returned error: {transferResponse.Error.Message} code {transferResponse.Error.Code}"); + logger.Info(() => $"[{LogCategory}] Retrying transfer using {ZanoWalletCommands.TransferSplit}"); + + var transferSplitResponse = await rpcClientWallet.ExecuteAsync(logger, ZanoWalletCommands.TransferSplit, ct, request); + + return await HandleTransferResponseAsync(transferSplitResponse, balances); + } + } + + return await HandleTransferResponseAsync(transferResponse, balances); + } + + private void ExtractAddressAndPaymentId(string input, out string address, out string paymentId) + { + paymentId = null; + var index = input.IndexOf(PayoutConstants.PayoutInfoSeperator); + + if(index != -1) + { + address = input[..index]; + + if(index + 1 < input.Length) + { + paymentId = input[(index + 1)..]; + + // ignore invalid payment ids + if(paymentId.Length != ZanoConstants.PaymentIdHexLength) + paymentId = null; + } + } + + else + address = input; + } + + private async Task PayoutToPaymentId(Balance balance, CancellationToken ct) + { + 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, coin, ct)) + return false; + + TransferRequest request; + var maxTransactionFees = (extraConfig?.MaxFee ?? ZanoConstants.MinimumTransactionFee) / coin.SmallestUnit; + + // build request + request = new TransferRequest + { + Destinations = new[] + { + new TransferDestination + { + Address = address, + Amount = (ulong) Math.Floor(balance.Amount * coin.SmallestUnit) + } + }, + + PaymentId = paymentId, + RevealSender = revealPoolAddress, + HideReceiver = hideMinerAddress + }; + + if(extraConfig?.KeepTransactionFees == true) + { + logger.Debug(() => $"[{LogCategory}] Pool does not pay the transaction fee, so that address will have its payout deducted with [{FormatAmount(maxTransactionFees)}]"); + + // build request + request = new TransferRequest + { + Destinations = new[] + { + new TransferDestination + { + Address = address, + Amount = (ulong) Math.Floor((balance.Amount > maxTransactionFees ? balance.Amount - maxTransactionFees : balance.Amount) * coin.SmallestUnit) + } + }, + + Fee = (extraConfig?.MaxFee ?? ZanoConstants.MinimumTransactionFee), + PaymentId = paymentId, + RevealSender = revealPoolAddress, + HideReceiver = hideMinerAddress + }; + } + + if(!isIntegratedAddress) + request.PaymentId = paymentId; + + if(!isIntegratedAddress) + logger.Info(() => $"[{LogCategory}] Paying {FormatAmount(balance.Amount)} to address {balance.Address} with paymentId {paymentId}"); + else + logger.Info(() => $"[{LogCategory}] Paying {FormatAmount(balance.Amount)} to integrated address {balance.Address}"); + + // send command + var result = await rpcClientWallet.ExecuteAsync(logger, ZanoWalletCommands.Transfer, ct, request); + + if(walletSupportsTransferSplit) + { + // gracefully handle error -4 (transaction would be too large. try /transfer_split) + if(result.Error?.Code == -4) + { + logger.Info(() => $"[{LogCategory}] Retrying transfer using {ZanoWalletCommands.TransferSplit}"); + + result = await rpcClientWallet.ExecuteAsync(logger, ZanoWalletCommands.TransferSplit, ct, request); + } + } + + return await HandleTransferResponseAsync(result, balance); + } + + #region IPayoutHandler + + public async Task ConfigureAsync(ClusterConfig cc, PoolConfig pc, CancellationToken ct) + { + Contract.RequiresNonNull(pc); + + poolConfig = pc; + clusterConfig = cc; + extraConfig = pc.PaymentProcessing.Extra.SafeExtensionDataAs(); + + logger = LogUtil.GetPoolScopedLogger(typeof(ZanoPayoutHandler), pc); + + // configure standard daemon + var jsonSerializerSettings = ctx.Resolve(); + + var daemonEndpoints = pc.Daemons + .Where(x => string.IsNullOrEmpty(x.Category)) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = ZanoConstants.DaemonRpcLocation; + + return x; + }) + .ToArray(); + + rpcClient = new RpcClient(daemonEndpoints.First(), jsonSerializerSettings, messageBus, pc.Id); + + // configure wallet daemon + var walletDaemonEndpoints = pc.Daemons + .Where(x => x.Category?.ToLower() == ZanoConstants.WalletDaemonCategory) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = ZanoConstants.DaemonRpcLocation; + + return x; + }) + .ToArray(); + + rpcClientWallet = new RpcClient(walletDaemonEndpoints.First(), jsonSerializerSettings, messageBus, pc.Id); + + // detect network + await UpdateNetworkTypeAsync(ct); + + // detect transfer_split support + var response = await rpcClientWallet.ExecuteAsync(logger, ZanoWalletCommands.TransferSplit, ct); + walletSupportsTransferSplit = response.Error.Code != ZanoConstants.RpcMethodNotFound; + + revealPoolAddress = extraConfig?.RevealPoolAddress ?? true; + hideMinerAddress = extraConfig?.HideMinerAddress ?? false; + } + + public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, CancellationToken ct) + { + Contract.RequiresNonNull(poolConfig); + Contract.RequiresNonNull(blocks); + + var coin = poolConfig.Template.As(); + var pageSize = 100; + var pageCount = (int) Math.Ceiling(blocks.Length / (double) pageSize); + var result = new List(); + + for(var i = 0; i < pageCount; i++) + { + // get a page full of blocks + var page = blocks + .Skip(i * pageSize) + .Take(pageSize) + .ToArray(); + + // NOTE: monerod does not support batch-requests + for(var j = 0; j < page.Length; j++) + { + var block = page[j]; + + var rpcResult = await rpcClient.ExecuteAsync(logger, + CNC.GetBlockHeaderByHeight, ct, + new GetBlockHeaderByHeightRequest + { + Height = block.BlockHeight + }); + + 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) + { + logger.Debug(() => $"[{LogCategory}] Daemon returned no header for block {block.BlockHeight}"); + continue; + } + + var blockHeader = rpcResult.Response.BlockHeader; + + // update progress + block.ConfirmationProgress = Math.Min(1.0d, (double) blockHeader.Depth / ZanoConstants.PayoutMinBlockConfirmations); + result.Add(block); + + messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); + + // orphaned? + if(blockHeader.IsOrphaned || blockHeader.Hash != block.TransactionConfirmationData) + { + block.Status = BlockStatus.Orphaned; + block.Reward = 0; + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + continue; + } + + // matured and spendable? + if(blockHeader.Depth >= ZanoConstants.PayoutMinBlockConfirmations) + { + block.Status = BlockStatus.Confirmed; + block.ConfirmationProgress = 1; + + block.Reward = (blockHeader.Reward / coin.SmallestUnit) * coin.BlockrewardMultiplier; + + logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + } + } + } + + return result.ToArray(); + } + + public async Task PayoutAsync(IMiningPool pool, Balance[] balances, CancellationToken ct) + { + Contract.RequiresNonNull(balances); + + var coin = poolConfig.Template.As(); + +#if !DEBUG // ensure we have peers + var infoResponse = await rpcClient.ExecuteAsync(logger, CNC.GetInfo, ct); + if (infoResponse.Error != null || infoResponse.Response == null || + infoResponse.Response.IncomingConnectionsCount + infoResponse.Response.OutgoingConnectionsCount < 2) + { + logger.Warn(() => $"[{LogCategory}] Payout aborted. Not enough peers (2 required)"); + return; + } +#endif + // validate addresses + balances = balances + .Where(x => + { + ExtractAddressAndPaymentId(x.Address, out var address, out _); + + var addressPrefix = CryptonoteBindings.DecodeAddress(address); + var addressIntegratedPrefix = CryptonoteBindings.DecodeIntegratedAddress(address); + + switch(networkType) + { + case ZanoNetworkType.Main: + if(addressPrefix != coin.AddressPrefix && + addressPrefix != coin.AuditableAddressPrefix && + addressIntegratedPrefix != coin.AddressPrefixIntegrated && + addressIntegratedPrefix != coin.AddressV2PrefixIntegrated && + addressIntegratedPrefix != coin.AuditableAddressIntegratedPrefix) + { + logger.Warn(() => $"[{LogCategory}] Excluding payment to invalid address: {x.Address}"); + return false; + } + + break; + + case ZanoNetworkType.Test: + if(addressPrefix != coin.AddressPrefixTestnet && + addressPrefix != coin.AuditableAddressPrefixTestnet && + addressIntegratedPrefix != coin.AddressPrefixIntegratedTestnet && + addressIntegratedPrefix != coin.AddressV2PrefixIntegratedTestnet && + addressIntegratedPrefix != coin.AuditableAddressIntegratedPrefixTestnet) + { + logger.Warn(() => $"[{LogCategory}] Excluding payment to invalid address: {x.Address}"); + return false; + } + + break; + } + + return true; + }) + .ToArray(); + + // simple balances first + var simpleBalances = balances + .Where(x => + { + ExtractAddressAndPaymentId(x.Address, out var address, out var paymentId); + + var hasPaymentId = paymentId != null; + var isIntegratedAddress = false; + var addressIntegratedPrefix = CryptonoteBindings.DecodeIntegratedAddress(address); + + switch(networkType) + { + case ZanoNetworkType.Main: + if(addressIntegratedPrefix == coin.AddressPrefixIntegrated || + addressIntegratedPrefix == coin.AddressV2PrefixIntegrated || + addressIntegratedPrefix == coin.AuditableAddressIntegratedPrefix) + isIntegratedAddress = true; + break; + + case ZanoNetworkType.Test: + if(addressIntegratedPrefix == coin.AddressPrefixIntegratedTestnet || + addressIntegratedPrefix == coin.AddressV2PrefixIntegratedTestnet || + addressIntegratedPrefix == coin.AuditableAddressIntegratedPrefixTestnet) + isIntegratedAddress = true; + break; + } + + return !hasPaymentId && !isIntegratedAddress; + }) + .OrderByDescending(x => x.Amount) + .ToArray(); + + if(simpleBalances.Length > 0) +#if false + await PayoutBatch(simpleBalances); +#else + { + var maxBatchSize = extraConfig?.MaximumDestinationPerTransfer ?? 256; + var pageSize = maxBatchSize; + var pageCount = (int) Math.Ceiling((double) simpleBalances.Length / pageSize); + + logger.Info(() => $"[{LogCategory}] Maximum of simultaneous destination address in a single transaction: {maxBatchSize}"); + + for(var i = 0; i < pageCount; i++) + { + var page = simpleBalances + .Skip(i * pageSize) + .Take(pageSize) + .ToArray(); + + if(!await PayoutBatch(page, ct)) + break; + } + } +#endif + // balances with paymentIds + var minimumPaymentToPaymentId = extraConfig?.MinimumPaymentToPaymentId ?? poolConfig.PaymentProcessing.MinimumPayment; + + var paymentIdBalances = balances.Except(simpleBalances) + .Where(x => x.Amount >= minimumPaymentToPaymentId) + .ToArray(); + + foreach(var balance in paymentIdBalances) + { + if(!await PayoutToPaymentId(balance, ct)) + break; + } + + // save wallet + await rpcClientWallet.ExecuteAsync(logger, ZanoWalletCommands.Store, ct); + } + + public double AdjustBlockEffort(double effort) + { + return effort; + } + + #endregion // IPayoutHandler +} diff --git a/src/Miningcore/Blockchain/Zano/ZanoPool.cs b/src/Miningcore/Blockchain/Zano/ZanoPool.cs new file mode 100644 index 0000000000..08295d1c90 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/ZanoPool.cs @@ -0,0 +1,994 @@ +using System.Globalization; +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using Autofac; +using AutoMapper; +using Microsoft.IO; +using Miningcore.Blockchain.Zano.StratumRequests; +using Miningcore.Blockchain.Zano.StratumResponses; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.JsonRpc; +using Miningcore.Messaging; +using Miningcore.Mining; +using Miningcore.Nicehash; +using Miningcore.Notifications.Messages; +using Miningcore.Payments; +using Miningcore.Persistence; +using Miningcore.Persistence.Repositories; +using Miningcore.Stratum; +using Miningcore.Time; +using Newtonsoft.Json; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Zano; + +[CoinFamily(CoinFamily.Zano)] +public class ZanoPool : PoolBase +{ + public ZanoPool(IComponentContext ctx, + JsonSerializerSettings serializerSettings, + IConnectionFactory cf, + IStatsRepository statsRepo, + IMapper mapper, + IMasterClock clock, + IMessageBus messageBus, + RecyclableMemoryStreamManager rmsm, + NicehashService nicehashService) : + base(ctx, serializerSettings, cf, statsRepo, mapper, clock, messageBus, rmsm, nicehashService) + { + } + + private long currentJobId; + + private ZanoJobManager manager; + private string minerAlgo; + private ZanoCoinTemplate coin; + + #region // Protocol V2 handlers - https://github.com/nicehash/Specifications/blob/master/EthereumStratum_NiceHash_v1.0.0.txt + + private async Task OnSubscribeAsync(StratumConnection connection, Timestamped tsRequest) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + 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)) + throw new StratumException(StratumError.MinusOne, "invalid request"); + + context.UserAgent = requestParams.FirstOrDefault()?.Trim(); + + var data = new object[] + { + new object[] + { + ZanoStratumMethods.MiningNotify, + connection.ConnectionId, + requestParams[1] + }, + "0000000000000000" + } + .ToArray(); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + var response = new JsonRpcResponse(data, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); + + // setup worker context + context.IsSubscribed = true; + } + + private async Task OnAuthorizeAsync(StratumConnection connection, Timestamped tsRequest) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + var requestParams = request.ParamsAs(); + var workerValue = requestParams?.Length > 0 ? requestParams[0] : "0"; + var password = requestParams?.Length > 1 ? requestParams[1] : null; + var passParts = password?.Split(PasswordControlVarsSeparator); + + // extract worker/miner + var workerParts = workerValue?.Split('.'); + context.Miner = workerParts?.Length > 0 ? workerParts[0].Trim() : null; + context.Worker = workerParts?.Length > 1 ? workerParts[1].Trim() : "0"; + + var addressToValidate = context.Miner; + + // extract paymentid + var index = context.Miner.IndexOf('#'); + if(index != -1) + { + var paymentId = context.Miner[(index + 1)..].Trim(); + + // validate + if(!string.IsNullOrEmpty(paymentId) && paymentId.Length != ZanoConstants.PaymentIdHexLength) + throw new StratumException(StratumError.MinusOne, "invalid payment id"); + + // re-append to address + addressToValidate = context.Miner[..index].Trim(); + context.Miner = addressToValidate + PayoutConstants.PayoutInfoSeperator + paymentId; + } + + // validate login + var result = manager.ValidateAddress(addressToValidate); + + context.IsAuthorized = result; + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] + var response = new JsonRpcResponse(context.IsAuthorized, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + // respond + await connection.RespondAsync(response); + + if(context.IsAuthorized) + { + // extract control vars from password + var staticDiff = GetStaticDiffFromPassparts(passParts); + + // Nicehash support + var nicehashDiff = await GetNicehashStaticMinDiff(context, coin.Name, coin.GetAlgorithmName()); + + if(nicehashDiff.HasValue) + { + if(!staticDiff.HasValue || nicehashDiff > staticDiff) + { + logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using API supplied difficulty of {nicehashDiff.Value}"); + + staticDiff = nicehashDiff; + } + + else + logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using miner supplied difficulty of {staticDiff.Value}"); + } + + // Static diff + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) + { + context.VarDiff = null; // disable vardiff + context.SetDifficulty(staticDiff.Value); + + logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); + } + + var job = CreateWorkerJob(connection); + + await connection.NotifyAsync(ZanoStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + await connection.NotifyAsync(ZanoStratumMethods.MiningNotify, job); + + // log association + if(!string.IsNullOrEmpty(context.Worker)) + logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {context.Worker}@{context.Miner}"); + else + logger.Info(() => $"[{connection.ConnectionId}] Authorized miner {context.Miner}"); + } + + else + { + if(clusterConfig?.Banning?.BanOnLoginFailure is null or true) + { + logger.Info(() => $"[{connection.ConnectionId}] Banning unauthorized worker {context.Miner} for {loginFailureBanTimeout.TotalSeconds} sec"); + + banManager.Ban(connection.RemoteEndpoint.Address, loginFailureBanTimeout); + + Disconnect(connection); + } + } + } + + private async Task OnSubmitAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + try + { + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + // validate worker + if(!context.IsAuthorized) + throw new StratumException(StratumError.MinusOne, "unauthorized"); + + // check age of submission (aged submissions are usually caused by high server load) + var requestAge = clock.Now - tsRequest.Timestamp.UtcDateTime; + + if(requestAge > maxShareAge) + { + logger.Warn(() => $"[{connection.ConnectionId}] Dropping stale share submission request (server overloaded?)"); + return; + } + + var requestParams = request.ParamsAs(); + + if(requestParams == null || requestParams.Length < 3 || requestParams.Any(string.IsNullOrEmpty)) + throw new StratumException(StratumError.MinusOne, "invalid request"); + + // recognize activity + context.LastActivity = clock.Now; + + ZanoWorkerJob job; + + lock(context) + { + var jobId = requestParams[1]; + + if((job = context.GetJob(jobId)) == null) + throw new StratumException(StratumError.MinusOne, "invalid jobid"); + } + + var submitRequest = new ZanoSubmitShareRequest + { + JobId = requestParams[1].StripHexPrefix(), + Nonce = requestParams[2].StripHexPrefix(), + Hash = requestParams[4].StripHexPrefix() + }; + + // dupe check + if(!job.Submissions.TryAdd(submitRequest.Nonce, true)) + throw new StratumException(StratumError.MinusOne, "duplicate share"); + + // submit + var share = await manager.SubmitShareAsync(connection, submitRequest, job, ct); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(new ZanoResponseBase(), request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); + + // publish + messageBus.SendMessage(share); + + // telemetry + PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, true); + + logger.Info(() => $"[{connection.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty * coin.ShareMultiplier, 3)}"); + + // update pool stats + if(share.IsBlockCandidate) + poolStats.LastPoolBlockTime = clock.Now; + + // update client stats + context.Stats.ValidShares++; + + await UpdateVarDiffAsync(connection, false, ct); + } + + catch(StratumException ex) + { + // telemetry + PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, false); + + // update client stats + context.Stats.InvalidShares++; + logger.Info(() => $"[{connection.ConnectionId}] Share rejected: {ex.Message} [{context.UserAgent}]"); + + // banning + ConsiderBan(connection, context, poolConfig.Banning); + + throw; + } + } + + #endregion // Protocol V2 handlers + + #region // Protocol V1 handlers - https://github.com/sammy007/open-ethereum-pool/blob/master/docs/STRATUM.md + + private async Task OnLoginAsync(StratumConnection connection, Timestamped tsRequest) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + var loginRequest = request.ParamsAs(); + + if(string.IsNullOrEmpty(loginRequest?.Login)) + throw new StratumException(StratumError.MinusOne, "missing login"); + + // extract worker/miner/paymentid + var split = loginRequest.Login.Split('.'); + context.Miner = split[0].Trim(); + context.Worker = split.Length > 1 ? split[1].Trim() : null; + context.UserAgent = loginRequest.UserAgent?.Trim(); + + var addressToValidate = context.Miner; + + // extract paymentid + var index = context.Miner.IndexOf('#'); + if(index != -1) + { + var paymentId = context.Miner[(index + 1)..].Trim(); + + // validate + if(!string.IsNullOrEmpty(paymentId) && paymentId.Length != ZanoConstants.PaymentIdHexLength) + throw new StratumException(StratumError.MinusOne, "invalid payment id"); + + // re-append to address + addressToValidate = context.Miner[..index].Trim(); + context.Miner = addressToValidate + PayoutConstants.PayoutInfoSeperator + paymentId; + } + + // validate login + var result = manager.ValidateAddress(addressToValidate); + + context.IsSubscribed = result; + context.IsAuthorized = result; + + if(context.IsAuthorized) + { + // extract control vars from password + var passParts = loginRequest.Password?.Split(PasswordControlVarsSeparator); + var staticDiff = GetStaticDiffFromPassparts(passParts); + + // Nicehash support + var nicehashDiff = await GetNicehashStaticMinDiff(context, manager.Coin.Name, manager.Coin.GetAlgorithmName()); + + if(nicehashDiff.HasValue) + { + if(!staticDiff.HasValue || nicehashDiff > staticDiff) + { + logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using API supplied difficulty of {nicehashDiff.Value}"); + + staticDiff = nicehashDiff; + } + + else + logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using miner supplied difficulty of {staticDiff.Value}"); + } + + // Static diff + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) + { + context.VarDiff = null; // disable vardiff + context.SetDifficulty(staticDiff.Value); + + logger.Info(() => $"[{connection.ConnectionId}] Static difficulty set to {staticDiff.Value}"); + } + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); + + // log association + if(!string.IsNullOrEmpty(context.Worker)) + logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {context.Worker}@{context.Miner}"); + else + logger.Info(() => $"[{connection.ConnectionId}] Authorized miner {context.Miner}"); + } + + else + { + await connection.RespondErrorAsync(StratumError.MinusOne, "invalid login", request.Id); + + if(clusterConfig?.Banning?.BanOnLoginFailure is null or true) + { + logger.Info(() => $"[{connection.ConnectionId}] Banning unauthorized worker {context.Miner} for {loginFailureBanTimeout.TotalSeconds} sec"); + + banManager.Ban(connection.RemoteEndpoint.Address, loginFailureBanTimeout); + + Disconnect(connection); + } + } + } + + private async Task OnSubmitLoginAsync(StratumConnection connection, Timestamped tsRequest) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + var requestParams = request.ParamsAs(); + + if(requestParams == null || requestParams.Length < 2 || requestParams.Any(string.IsNullOrEmpty)) + throw new StratumException(StratumError.MinusOne, "invalid request"); + + // extract worker/miner/paymentid + var workerValue = requestParams?.Length > 0 ? requestParams[0] : null; + + if(string.IsNullOrEmpty(workerValue)) + throw new StratumException(StratumError.MinusOne, "missing login"); + + var split = workerValue.Split('.'); + context.Miner = split[0].Trim(); + context.Worker = split.Length > 1 ? split[1].Trim() : null; + var password = requestParams?.Length > 1 ? requestParams[1] : null; + context.UserAgent = requestParams?.Length > 2 ? requestParams[2].Trim() : null; + + var addressToValidate = context.Miner; + + // extract paymentid + var index = context.Miner.IndexOf('#'); + if(index != -1) + { + var paymentId = context.Miner[(index + 1)..].Trim(); + + // validate + if(!string.IsNullOrEmpty(paymentId) && paymentId.Length != ZanoConstants.PaymentIdHexLength) + throw new StratumException(StratumError.MinusOne, "invalid payment id"); + + // re-append to address + addressToValidate = context.Miner[..index].Trim(); + context.Miner = addressToValidate + PayoutConstants.PayoutInfoSeperator + paymentId; + } + + // validate login + var result = manager.ValidateAddress(addressToValidate); + + context.IsSubscribed = result; + context.IsAuthorized = result; + + if(context.IsAuthorized) + { + // extract control vars from password + var passParts = password?.Split(PasswordControlVarsSeparator); + var staticDiff = GetStaticDiffFromPassparts(passParts); + + // Nicehash support + var nicehashDiff = await GetNicehashStaticMinDiff(context, manager.Coin.Name, manager.Coin.GetAlgorithmName()); + + if(nicehashDiff.HasValue) + { + if(!staticDiff.HasValue || nicehashDiff > staticDiff) + { + logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using API supplied difficulty of {nicehashDiff.Value}"); + + staticDiff = nicehashDiff; + } + + else + logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using miner supplied difficulty of {staticDiff.Value}"); + } + + // Static diff + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) + { + context.VarDiff = null; // disable vardiff + context.SetDifficulty(staticDiff.Value); + + logger.Info(() => $"[{connection.ConnectionId}] Static difficulty set to {staticDiff.Value}"); + } + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); + + // log association + if(!string.IsNullOrEmpty(context.Worker)) + logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {context.Worker}@{context.Miner}"); + else + logger.Info(() => $"[{connection.ConnectionId}] Authorized miner {context.Miner}"); + } + + else + { + await connection.RespondErrorAsync(StratumError.MinusOne, "invalid login", request.Id); + + if(clusterConfig?.Banning?.BanOnLoginFailure is null or true) + { + logger.Info(() => $"[{connection.ConnectionId}] Banning unauthorized worker {context.Miner} for {loginFailureBanTimeout.TotalSeconds} sec"); + + banManager.Ban(connection.RemoteEndpoint.Address, loginFailureBanTimeout); + + Disconnect(connection); + } + } + } + + private async Task OnGetJobAsync(StratumConnection connection, Timestamped tsRequest) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + // authorized worker + if(!context.IsAuthorized) + throw new StratumException(StratumError.MinusOne, "unauthorized"); + + var job = CreateWorkerJob(connection); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(job, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + // respond + await connection.RespondAsync(response); + } + + private async Task OnSubmitWorkAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + try + { + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + // validate worker + if(!context.IsAuthorized) + throw new StratumException(StratumError.MinusOne, "unauthorized"); + + // check age of submission (aged submissions are usually caused by high server load) + var requestAge = clock.Now - tsRequest.Timestamp.UtcDateTime; + + if(requestAge > maxShareAge) + { + logger.Warn(() => $"[{connection.ConnectionId}] Dropping stale share submission request (server overloaded?)"); + return; + } + + var requestParams = request.ParamsAs(); + + if(requestParams == null || requestParams.Length < 3 || requestParams.Any(string.IsNullOrEmpty)) + throw new StratumException(StratumError.MinusOne, "invalid request"); + + // recognize activity + context.LastActivity = clock.Now; + + ZanoWorkerJob job; + + lock(context) + { + var jobId = requestParams[1]; + + if((job = context.GetJob(jobId)) == null) + throw new StratumException(StratumError.MinusOne, "invalid jobid"); + } + + var submitRequest = new ZanoSubmitShareRequest + { + JobId = requestParams[1].StripHexPrefix(), + Nonce = requestParams[0].StripHexPrefix(), + Hash = requestParams[2].StripHexPrefix() + }; + + // dupe check + if(!job.Submissions.TryAdd(submitRequest.Nonce, true)) + throw new StratumException(StratumError.MinusOne, "duplicate share"); + + // submit + var share = await manager.SubmitShareAsync(connection, submitRequest, job, ct); + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(new ZanoResponseBase(), request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); + + // publish + messageBus.SendMessage(share); + + // telemetry + PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, true); + + logger.Info(() => $"[{connection.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty * coin.ShareMultiplier, 3)}"); + + // update pool stats + if(share.IsBlockCandidate) + poolStats.LastPoolBlockTime = clock.Now; + + // update client stats + context.Stats.ValidShares++; + + await UpdateVarDiffAsync(connection, false, ct); + } + + catch(StratumException ex) + { + // telemetry + PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, false); + + // update client stats + context.Stats.InvalidShares++; + logger.Info(() => $"[{connection.ConnectionId}] Share rejected: {ex.Message} [{context.UserAgent}]"); + + // banning + ConsiderBan(connection, context, poolConfig.Banning); + + throw; + } + } + + #endregion // Protocol V1 handlers + + private object[] CreateWorkerJob(StratumConnection connection) + { + var context = connection.ContextAs(); + var job = manager.PrepareWorkerJob(context.Difficulty); + + logger.Debug(() => $"JobId: {job.Id} - Target: {job.Target} - Height: {job.Height} - SeedHash: {job.SeedHash}"); + + // should never happen + if(string.IsNullOrEmpty(job.Id) || string.IsNullOrEmpty(job.Target)) + return null; + + var result = new object[] + { + job.Id, + job.SeedHash, + job.Target, + job.Height + }; + + // update context + lock(context) + { + context.AddJob(job, 4); + } + + return result; + } + + private string NextJobId() + { + return Interlocked.Increment(ref currentJobId).ToString(CultureInfo.InvariantCulture); + } + + private async Task OnNewJobAsync() + { + logger.Info(() => "Broadcasting jobs"); + + await Guard(() => ForEachMinerAsync(async (connection, ct) => + { + var context = connection.ContextAs(); + + var job = CreateWorkerJob(connection); + + switch(context.ProtocolVersion) + { + case 1: + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(job); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + // notify + await connection.RespondAsync(response); + break; + + case 2: + // varDiff: if the client has a pending difficulty change, apply it now + if(context.ApplyPendingDifficulty()) + await connection.NotifyAsync(ZanoStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + + // notify + await connection.NotifyAsync(ZanoStratumMethods.MiningNotify, job); + break; + } + })); + } + + #region Overrides + + public override void Configure(PoolConfig pc, ClusterConfig cc) + { + coin = pc.Template.As(); + + base.Configure(pc, cc); + } + + protected override async Task SetupJobManager(CancellationToken ct) + { + manager = ctx.Resolve(); + manager.Configure(poolConfig, clusterConfig); + + await manager.StartAsync(ct); + + if(poolConfig.EnableInternalStratum == true) + { + minerAlgo = GetMinerAlgo(); + + disposables.Add(manager.Blocks + .Select(_ => Observable.FromAsync(() => + Guard(OnNewJobAsync, + ex=> logger.Debug(() => $"{nameof(OnNewJobAsync)}: {ex.Message}")))) + .Concat() + .Subscribe(_ => { }, ex => + { + logger.Debug(ex, nameof(OnNewJobAsync)); + })); + + // start with initial blocktemplate + await manager.Blocks.Take(1).ToTask(ct); + } + + else + { + // keep updating NetworkStats + disposables.Add(manager.Blocks.Subscribe()); + } + } + + private string GetMinerAlgo() + { + switch(manager.Coin.Hash) + { + case CryptonightHashType.ProgPowZ: + return "cn/wow"; // wownero specific change to include algo in job to miner + } + + return null; + } + + protected override async Task InitStatsAsync(CancellationToken ct) + { + await base.InitStatsAsync(ct); + + blockchainStats = manager.BlockchainStats; + } + + protected override WorkerContextBase CreateWorkerContext() + { + return new ZanoWorkerContext(); + } + + protected void EnsureProtocolVersion(ZanoWorkerContext context, int version) + { + if(context.ProtocolVersion != version) + throw new StratumException(StratumError.MinusOne, $"protocol mismatch"); + } + + protected override async Task OnRequestAsync(StratumConnection connection, + Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + try + { + switch(request.Method) + { + // V2/Nicehash Stratum Methods + case ZanoStratumMethods.Subscribe: + context.ProtocolVersion = 2; // lock in protocol version + + await OnSubscribeAsync(connection, tsRequest); + break; + + case ZanoStratumMethods.Authorize: + EnsureProtocolVersion(context, 2); + + await OnAuthorizeAsync(connection, tsRequest); + break; + + case ZanoStratumMethods.SubmitShare: + EnsureProtocolVersion(context, 2); + + await OnSubmitAsync(connection, tsRequest, ct); + break; + + case ZanoStratumMethods.ExtraNonceSubscribe: + EnsureProtocolVersion(context, 2); + + // Pretend to support it even though we actually do not. Some miners drop the connection upon receiving an error from this + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] + var responseSubscribe = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + responseSubscribe.Extra = new Dictionary(); + responseSubscribe.Extra["error"] = null; + } + + await connection.RespondAsync(responseSubscribe); + break; + + case ZanoStratumMethods.Login: + context.ProtocolVersion = 1; // lock in protocol version + + await OnLoginAsync(connection, tsRequest); + break; + + case ZanoStratumMethods.SubmitLogin: + context.ProtocolVersion = 1; // lock in protocol version + + await OnSubmitLoginAsync(connection, tsRequest); + break; + + case ZanoStratumMethods.GetWork: + case ZanoStratumMethods.GetJob: + EnsureProtocolVersion(context, 1); + + await OnGetJobAsync(connection, tsRequest); + break; + + case ZanoStratumMethods.Submit: + EnsureProtocolVersion(context, 2); + + await OnSubmitAsync(connection, tsRequest, ct); + break; + + case ZanoStratumMethods.SubmitWork: + EnsureProtocolVersion(context, 1); + + await OnSubmitWorkAsync(connection, tsRequest, ct); + break; + + case ZanoStratumMethods.KeepAlive: + // recognize activity + context.LastActivity = clock.Now; + + // For some reasons, we would never send a reply here :/ + // But the official XMRig documentation is explicit, we should reply: https://xmrig.com/docs/extensions/keepalive + // XMRig is such a gift, i wish more mining pool operators were like them and valued open-source, the same way the XMRig devs do + + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var responseKeepAlive = new JsonRpcResponse(new ZanoKeepAliveResponse(), request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + responseKeepAlive.Extra = new Dictionary(); + responseKeepAlive.Extra["error"] = null; + } + + await connection.RespondAsync(responseKeepAlive); + break; + + case ZanoStratumMethods.SubmitHashrate: + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [We miss you Oliver <3 We miss you so much <3 Respect the goddamn standards Nicehash :(] + var responseSubmitHashrate = new JsonRpcResponse(true, request.Id); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + responseSubmitHashrate.Extra = new Dictionary(); + responseSubmitHashrate.Extra["error"] = null; + } + + await connection.RespondAsync(responseSubmitHashrate); + break; + + default: + logger.Debug(() => $"[{connection.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); + + await connection.RespondErrorAsync(StratumError.Other, $"Unsupported request {request.Method}", request.Id); + break; + } + } + + catch(StratumException ex) + { + await connection.RespondErrorAsync(ex.Code, ex.Message, request.Id, false); + } + } + + public override double HashrateFromShares(double shares, double interval) + { + var result = shares / interval; + + if(coin.HashrateMultiplier.HasValue) + result *= coin.HashrateMultiplier.Value; + + return result; + } + + public override double ShareMultiplier => coin.ShareMultiplier; + + protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, double newDiff, CancellationToken ct) + { + await base.OnVarDiffUpdateAsync(connection, newDiff, ct); + + if(connection.Context.ApplyPendingDifficulty()) + { + var context = connection.ContextAs(); + + var job = CreateWorkerJob(connection); + + switch(context.ProtocolVersion) + { + case 1: + // Nicehash's stupid validator insists on "error" property present + // in successful responses which is a violation of the JSON-RPC spec + // [Respect the goddamn standards Nicehack :(] + var response = new JsonRpcResponse(job); + + if(context.IsNicehash || poolConfig.EnableAsicBoost == true) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + // re-send job + await connection.RespondAsync(response); + break; + + case 2: + await connection.NotifyAsync(ZanoStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + + // re-send job + await connection.NotifyAsync(ZanoStratumMethods.MiningNotify, job); + break; + } + } + } + + #endregion // Overrides +} diff --git a/src/Miningcore/Blockchain/Zano/ZanoStratumMethods.cs b/src/Miningcore/Blockchain/Zano/ZanoStratumMethods.cs new file mode 100644 index 0000000000..eefe7ee498 --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/ZanoStratumMethods.cs @@ -0,0 +1,84 @@ +namespace Miningcore.Blockchain.Zano; + +public class ZanoStratumMethods +{ + /// + /// Used to subscribe to work from a server, required before all other communication. + /// + public const string Subscribe = "mining.subscribe"; + + /// + /// Used to authorize a worker, required before any shares can be submitted. + /// + public const string Authorize = "mining.authorize"; + + /// + /// Basically the idea is that miner remember the last difficulty given by the previous mining session and it sends mining.suggest_difficulty(difficulty) on the beginning of the next session (it may be sent before mining.subscribe or mining.resume, but it should not be a requirement) + /// + public const string SuggestDifficulty = "mining.suggest_difficulty"; + + /// + /// Used to push new work to the miner. Previous work should be aborted if Clean Jobs = true! + /// + public const string MiningNotify = "mining.notify"; + + /// + /// Used to submit shares + /// + public const string SubmitShare = "mining.submit"; + + /// + /// Used to signal the miner to stop submitting shares under the new difficulty. + /// + public const string SetDifficulty = "mining.set_difficulty"; + + /// + /// Used to subscribe to work from a server, required before all other communication. + /// + public const string ExtraNonceSubscribe = "mining.extranonce.subscribe"; + + /// + /// Used to subscribe to work + /// + public const string Login = "login"; + + /// + /// Used to subscribe to work + /// + public const string SubmitLogin = "eth_submitLogin"; + + /// + /// New job notification + /// + public const string JobNotify = "job"; + + /// + /// Get Job request + /// + public const string GetWork = "eth_getWork"; + + /// + /// Get Job request + /// + public const string GetJob = "getjob"; + + /// + /// Submit share request + /// + public const string SubmitWork = "eth_submitWork"; + + /// + /// Submit share request + /// + public const string Submit = "submit"; + + /// + /// Keep alive request + /// + public const string KeepAlive = "keepalived"; + + /// + /// Ignored + /// + public const string SubmitHashrate = "eth_submitHashrate"; +} diff --git a/src/Miningcore/Blockchain/Zano/ZanoWorkerContext.cs b/src/Miningcore/Blockchain/Zano/ZanoWorkerContext.cs new file mode 100644 index 0000000000..c3ff48e53e --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/ZanoWorkerContext.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Linq; +using Miningcore.Mining; + +namespace Miningcore.Blockchain.Zano; + +public class ZanoWorkerContext : WorkerContextBase +{ + /// + /// Usually a wallet address + /// NOTE: May include paymentid (seperated by a dot .) + /// + public override string Miner { get; set; } + + /// + /// Arbitrary worker identififer for miners using multiple rigs + /// + public override string Worker { get; set; } + + /// + /// Stratum protocol version + /// + public int ProtocolVersion { get; set; } + + /// + /// Current N job(s) assigned to this worker + /// + public Queue validJobs { get; private set; } = new(); + + public virtual void AddJob(ZanoWorkerJob job, int maxActiveJobs) + { + if(!validJobs.Contains(job)) + validJobs.Enqueue(job); + + while(validJobs.Count > maxActiveJobs) + validJobs.Dequeue(); + } + + public ZanoWorkerJob GetJob(string jobId) + { + return validJobs.ToArray().FirstOrDefault(x => x.Id == jobId); + } +} diff --git a/src/Miningcore/Blockchain/Zano/ZanoWorkerJob.cs b/src/Miningcore/Blockchain/Zano/ZanoWorkerJob.cs new file mode 100644 index 0000000000..2a9f830e3d --- /dev/null +++ b/src/Miningcore/Blockchain/Zano/ZanoWorkerJob.cs @@ -0,0 +1,21 @@ +using System.Collections.Concurrent; + +namespace Miningcore.Blockchain.Zano; + +public class ZanoWorkerJob +{ + public ZanoWorkerJob(string jobId, double difficulty) + { + Id = jobId; + Difficulty = difficulty; + } + + public string Id { get; } + public string Height { get; set; } + public uint ExtraNonce { get; set; } + public double Difficulty { get; set; } + public string Target { get; set; } + public string SeedHash { get; set; } + + public readonly ConcurrentDictionary Submissions = new(StringComparer.OrdinalIgnoreCase); +} diff --git a/src/Miningcore/CoinMarketCap/CoinMarketCapConstants.cs b/src/Miningcore/CoinMarketCap/CoinMarketCapConstants.cs new file mode 100644 index 0000000000..a95bdb88d5 --- /dev/null +++ b/src/Miningcore/CoinMarketCap/CoinMarketCapConstants.cs @@ -0,0 +1,7 @@ +namespace Miningcore.CoinMarketCap +{ + public static class CoinMarketCapConstants + { + public static readonly string HttpKeyword = "CoinMarketCap"; + } +} diff --git a/src/Miningcore/CoinMarketCap/CoinMarketCapService.cs b/src/Miningcore/CoinMarketCap/CoinMarketCapService.cs new file mode 100644 index 0000000000..0200a01571 --- /dev/null +++ b/src/Miningcore/CoinMarketCap/CoinMarketCapService.cs @@ -0,0 +1,54 @@ +using Newtonsoft.Json; +using Miningcore.Api.Requests; + +namespace Miningcore.CoinMarketCap +{ + public class CoinMarketCapService + { + private readonly IHttpClientFactory _factory; + + public CoinMarketCapService(IHttpClientFactory factory) + { + _factory = factory; + } + + public async Task GetCryptoQuoteAsync(string symbol) + { + using var client = _factory.CreateClient(CoinMarketCapConstants.HttpKeyword); + var response = await client.GetAsync($"cryptocurrency/quotes/latest?symbol={symbol}"); + var result = await response.Content.ReadAsStringAsync(); + var resultValue = JsonConvert.DeserializeObject(result); + + var slugs = string.Join(",", resultValue.Data.Select(Q => string.Join(",", Q.Value.Select(Q => Q.Slug)))).ToLower().Replace(",,", ","); + slugs = slugs.Substring(slugs.Length -1 , 1) == "," ? slugs.Remove(slugs.Length - 1) : slugs; + response = await client.GetAsync($"cryptocurrency/info?slug={slugs}"); + var resultLogo = await response.Content.ReadAsStringAsync(); + var resultValueInfo = JsonConvert.DeserializeObject(resultLogo); + var allDictionary = resultValueInfo?.Data?.GroupBy(Q => Q.Value.Symbol) + .ToDictionary( + g => g.Key, + g => g.ToDictionary( + x => x.Key.ToString(), + x => x.Value.Logo + ) + ) ?? new Dictionary>(); + foreach(var item in resultValue.Data) + { + if(allDictionary.Count == 0) + break; + if(allDictionary.TryGetValue(item.Key, out Dictionary logoDictionary)) + { + foreach(var cryptoData in item.Value) + { + if(logoDictionary.TryGetValue(cryptoData.Id.ToString(), out string logo)) + { + cryptoData.Logo = logo; + } + } + } + } + return resultValue; + } + } +} + diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index c81f9c522d..bc49cedf00 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -51,6 +51,15 @@ public enum CoinFamily [EnumMember(Value = "progpow")] Progpow, + + [EnumMember(Value = "warthog")] + Warthog, + + [EnumMember(Value = "xelis")] + Xelis, + + [EnumMember(Value = "zano")] + Zano, } public abstract partial class CoinTemplate @@ -130,12 +139,6 @@ public abstract partial class CoinTemplate [JsonProperty(Order = -9)] public string Discord { get; set; } - /// - /// Telegram Group Link - /// - [JsonProperty(Order = -9)] - public string Github { get; set; } - /// /// Telegram Group Link /// @@ -166,6 +169,9 @@ public abstract partial class CoinTemplate {CoinFamily.Kaspa, typeof(KaspaCoinTemplate)}, {CoinFamily.Nexa, typeof(BitcoinTemplate)}, {CoinFamily.Progpow, typeof(ProgpowCoinTemplate)}, + {CoinFamily.Warthog, typeof(WarthogCoinTemplate)}, + {CoinFamily.Xelis, typeof(XelisCoinTemplate)}, + {CoinFamily.Zano, typeof(ZanoCoinTemplate)}, }; } @@ -202,13 +208,12 @@ public class BitcoinNetworkParams [JsonConverter(typeof(StringEnumConverter), true)] public BitcoinSubfamily Subfamily { get; set; } + public JObject MerkleTreeHasher { get; set; } public JObject CoinbaseHasher { get; set; } public JObject HeaderHasher { get; set; } + public JObject ShareHasher { get; set; } public JObject BlockHasher { get; set; } - [JsonProperty("diff1")] - public string Diff1 { get; set; } - [JsonProperty("posBlockHasher")] public JObject PoSBlockHasher { get; set; } @@ -237,19 +242,7 @@ public class BitcoinNetworkParams public bool HasFounderFee { get; set; } [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool HasDevFee { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool HasCommunity { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool HasDeveloper { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool HasDataMining { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool HasMinerDevFund { get; set; } + public bool HasFortuneReward { get; set; } [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool HasMinerFund { get; set; } @@ -261,7 +254,7 @@ public class BitcoinNetworkParams public bool HasCoinbaseDevReward { get; set; } [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool HasFoundation { get; set; } + public bool HasCoinbaseStakingReward { get; set; } [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] [DefaultValue(1.0d)] @@ -393,15 +386,6 @@ public enum CryptonightHashType [EnumMember(Value = "randomarq")] RandomARQ, - [EnumMember(Value = "randomscash")] - RandomSCASH, - - [EnumMember(Value = "randomxeq")] - RandomXEQ, - - [EnumMember(Value = "panthera")] - Panthera, - [EnumMember(Value = "cn0")] Cryptonight0, @@ -441,9 +425,6 @@ public enum CryptonightHashType [EnumMember(Value = "cn-xao")] CryptonightXAO, - [EnumMember(Value = "flex")] - Flex, - [EnumMember(Value = "gr")] Ghostrider, @@ -476,6 +457,9 @@ public enum CryptonightHashType [EnumMember(Value = "argon_wrkz")] ArgonWRKZ, + + [EnumMember(Value = "progpowz")] + ProgPowZ, } public partial class CryptonoteCoinTemplate : CoinTemplate @@ -569,10 +553,6 @@ public partial class CryptonoteCoinTemplate : CoinTemplate [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] [DefaultValue(1.0d)] public decimal BlockrewardMultiplier { get; set; } - - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public int? CoinbaseMinConfimations { get; set; } - } public enum EquihashSubfamily @@ -696,6 +676,14 @@ public partial class EthereumCoinTemplate : CoinTemplate [DefaultValue(EthereumSubfamily.None)] [JsonConverter(typeof(StringEnumConverter), true)] public EthereumSubfamily Subfamily { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue("eth")] + public string RpcMethodPrefix { get; set; } = "eth"; + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(2)] + public int MaxUncles { get; set; } = 2; /// /// Which hashing algorithm to use. (ethash, etchash, ubqhash or ethashb3) @@ -705,6 +693,37 @@ public partial class EthereumCoinTemplate : CoinTemplate public partial class KaspaCoinTemplate : CoinTemplate { + /// + /// Prefix of a valid mainnet address + /// See: parameter -> Bech32PrefixKaspa in blob/master/util/address.go + /// + public string AddressBech32Prefix { get; set; } + + /// + /// Prefix of a valid devnet address + /// See: parameter -> Bech32PrefixKaspaDev in blob/master/util/address.go + /// + public string AddressBech32PrefixDevnet { get; set; } + + /// + /// Prefix of a valid simnet address + /// See: parameter -> Bech32PrefixKaspaSim in blob/master/util/address.go + /// + public string AddressBech32PrefixSimnet { get; set; } + + /// + /// Prefix of a valid testnet address + /// See: parameter -> Bech32PrefixKaspaTest in blob/master/util/address.go + /// + public string AddressBech32PrefixTestnet { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(1.0d)] + public double ShareMultiplier { get; set; } = 1.0d; + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(4294967296.0d)] + public double HashrateMultiplier { get; set; } = 4294967296.0d; } public partial class ProgpowCoinTemplate : BitcoinTemplate @@ -715,6 +734,136 @@ public partial class ProgpowCoinTemplate : BitcoinTemplate public string Progpower { get; set; } = "kawpow"; } +public partial class WarthogCoinTemplate : CoinTemplate +{ +} + +public partial class XelisCoinTemplate : CoinTemplate +{ + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(1.0d)] + public double ShareMultiplier { get; set; } = 1.0d; +} + +public enum ZanoSubfamily +{ + [EnumMember(Value = "none")] + None, +} + +public partial class ZanoCoinTemplate : CoinTemplate +{ + [JsonProperty(Order = -7, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(ZanoSubfamily.None)] + [JsonConverter(typeof(StringEnumConverter), true)] + public ZanoSubfamily Subfamily { get; set; } + + /// + /// Broader Cryptonight hash family + /// + [JsonConverter(typeof(StringEnumConverter), true)] + [JsonProperty(Order = -5)] + public CryptonightHashType Hash { get; set; } + + /// + /// Broader Cryptonight hash variant + /// + [JsonProperty(Order = -4, DefaultValueHandling = DefaultValueHandling.Include)] + public int HashVariant { get; set; } + + /// + /// Blob type in order to build the correct blob from blobtemplate + /// + [JsonProperty(Order = -4, DefaultValueHandling = DefaultValueHandling.Include)] + public int BlobType { get; set; } + + /// + /// Conceal network hashrate = `Difficulty / DifficultyTarget` + /// See: parameter -> DIFFICULTY_TARGET in src/currency_core/currency_config.h + /// + public ulong DifficultyTarget { get; set; } + + /// + /// Smallest unit for Blockreward formatting + /// + public decimal SmallestUnit { get; set; } + + /// + /// Prefix of a valid address + /// See: parameter -> CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX in src/currency_core/currency_config.h + /// + public ulong AddressPrefix { get; set; } + + /// + /// Prefix of a valid testnet-address + /// See: parameter -> CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX in src/currency_core/currency_config.h + /// + public ulong AddressPrefixTestnet { get; set; } + + /// + /// Prefix of a valid integrated address + /// See: parameter -> CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX in src/currency_core/currency_config.h + /// + public ulong AddressPrefixIntegrated { get; set; } + + /// + /// Prefix of a valid integrated testnet-address + /// See: parameter -> CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX in src/currency_core/currency_config.h + /// + public ulong AddressPrefixIntegratedTestnet { get; set; } + + /// + /// Prefix of a valid integrated address-v2 + /// See: parameter -> CURRENCY_PUBLIC_INTEG_ADDRESS_V2_BASE58_PREFIX in src/currency_core/currency_config.h + /// + public ulong AddressV2PrefixIntegrated { get; set; } + + /// + /// Prefix of a valid integrated testnet-address-v2 + /// See: parameter -> CURRENCY_PUBLIC_INTEG_ADDRESS_V2_BASE58_PREFIX in src/currency_core/currency_config.h + /// + public ulong AddressV2PrefixIntegratedTestnet { get; set; } + + /// + /// Sub Prefix of a valid auditable-address + /// See: namespace config -> CURRENCY_PUBLIC_AUDITABLE_ADDRESS_BASE58_PREFIX in src/cryptonote_config.h + /// + public ulong AuditableAddressPrefix { get; set; } + + /// + /// Sub Prefix of a valid testnet-auditable-address + /// See: namespace config -> CURRENCY_PUBLIC_AUDITABLE_ADDRESS_BASE58_PREFIX in src/cryptonote_config.h + /// + public ulong AuditableAddressPrefixTestnet { get; set; } + + /// + /// Sub Prefix of a valid integrated auditable-address + /// See: namespace config -> CURRENCY_PUBLIC_AUDITABLE_INTEG_ADDRESS_BASE58_PREFIX in src/cryptonote_config.h + /// + public ulong AuditableAddressIntegratedPrefix { get; set; } + + /// + /// Sub Prefix of a valid integrated testnet-auditable-address + /// See: namespace config -> CURRENCY_PUBLIC_AUDITABLE_INTEG_ADDRESS_BASE58_PREFIX in src/cryptonote_config.h + /// + public ulong AuditableAddressIntegratedPrefixTestnet { 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; + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(1.0d)] + public double? HashrateMultiplier { get; set; } = 1.0d; +} + #endregion // Coin Definitions public enum PayoutScheme @@ -935,6 +1084,8 @@ public partial class PoolShareBasedBanningConfig public int CheckThreshold { get; set; } // Check stats when this many shares have been submitted public double InvalidPercent { get; set; } // What percent of invalid shares triggers ban public int Time { get; set; } // How many seconds to ban worker for + public double? MinerEffortPercent { get; set; } // What percent of effort triggers ban + public int? MinerEffortTime { get; set; } // How many seconds to ban worker for } public partial class PoolPaymentProcessingConfig @@ -1177,6 +1328,15 @@ public partial class PoolConfig /// public bool? EnableInternalStratum { get; set; } + /// + /// Don't let the name fool you, "ASIC BOOST" is just the most annoying decision ever made. + /// Probably under the stupid incentives from NiceHack (NiceHash), some ASIC manufacturers and all their IDIOT partners in crime. + /// They literally came up with the STUPID idea of breaking the JSON-RPC standards by sending the "error" field even when there is no error, IDIOTS!!! + /// If true, stratum answer will always have the field "error" present in all JSON-RPC responses + /// Default: False + /// + public bool? EnableAsicBoost { get; set; } + /// /// Interval in seconds for performing sweeps over connected miners operating on a too high diff to submit shares and adjust varDiff down /// @@ -1189,6 +1349,12 @@ public partial class PoolConfig public IDictionary Extra { get; set; } } +public partial class CoinMarketCapApi +{ + public bool Enabled { get; set; } + public string Key { get; set; } +} + public partial class ClusterConfig { /// @@ -1239,4 +1405,6 @@ public partial class ClusterConfig [Required] public PoolConfig[] Pools { get; set; } + + public CoinMarketCapApi CoinMarketCapApi { get; set; } } diff --git a/src/Miningcore/Configuration/ClusterConfigExtensions.cs b/src/Miningcore/Configuration/ClusterConfigExtensions.cs index dd1cb09ef6..a73a509f03 100644 --- a/src/Miningcore/Configuration/ClusterConfigExtensions.cs +++ b/src/Miningcore/Configuration/ClusterConfigExtensions.cs @@ -55,12 +55,18 @@ public partial class BitcoinTemplate { public BitcoinTemplate() { + merkleTreeHasherValue = new Lazy(() => + HashAlgorithmFactory.GetHash(ComponentContext, MerkleTreeHasher)); + coinbaseHasherValue = new Lazy(() => HashAlgorithmFactory.GetHash(ComponentContext, CoinbaseHasher)); headerHasherValue = new Lazy(() => HashAlgorithmFactory.GetHash(ComponentContext, HeaderHasher)); + shareHasherValue = new Lazy(() => + HashAlgorithmFactory.GetHash(ComponentContext, ShareHasher)); + blockHasherValue = new Lazy(() => HashAlgorithmFactory.GetHash(ComponentContext, BlockHasher)); @@ -68,15 +74,19 @@ public BitcoinTemplate() HashAlgorithmFactory.GetHash(ComponentContext, PoSBlockHasher)); } + private readonly Lazy merkleTreeHasherValue; private readonly Lazy coinbaseHasherValue; private readonly Lazy headerHasherValue; + private readonly Lazy shareHasherValue; private readonly Lazy blockHasherValue; private readonly Lazy posBlockHasherValue; public IComponentContext ComponentContext { get; [UsedImplicitly] init; } + public IHashAlgorithm MerkleTreeHasherValue => merkleTreeHasherValue.Value; public IHashAlgorithm CoinbaseHasherValue => coinbaseHasherValue.Value; public IHashAlgorithm HeaderHasherValue => headerHasherValue.Value; + public IHashAlgorithm ShareHasherValue => shareHasherValue.Value; public IHashAlgorithm BlockHasherValue => blockHasherValue.Value; public IHashAlgorithm PoSBlockHasherValue => posBlockHasherValue.Value; @@ -99,12 +109,20 @@ public BitcoinNetworkParams GetNetwork(ChainName chain) public override string GetAlgorithmName() { - var hash = HeaderHasherValue; + switch(Symbol) + { + case "HNS": + return HeaderHasherValue.GetType().Name + " + " + ShareHasherValue.GetType().Name; + case "KCN": + return HeaderHasherValue.GetType().Name; + default: + 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; + return hash.GetType().Name; + } } #endregion @@ -258,17 +276,21 @@ public override string GetAlgorithmName() { switch(Symbol) { - case "CSS": - case "PUG": + case "AIX": + return "AstrixHash"; case "KLS": + return "Karlsenhashv2"; + case "CSS": case "NTL": case "NXL": + case "PUG": return "Karlsenhash"; case "CAS": case "HTN": - case "KODA": case "PYI": return "Pyrinhash"; + case "SPR": + return " SpectreX"; default: // TODO: return variant return "kHeavyHash"; @@ -300,6 +322,54 @@ public override string GetAlgorithmName() #endregion } +public partial class WarthogCoinTemplate +{ + #region Overrides of CoinTemplate + + public override string GetAlgorithmName() + { + return "PoBW"; + } + + #endregion +} + +public partial class XelisCoinTemplate +{ + #region Overrides of CoinTemplate + + public override string GetAlgorithmName() + { + return "XelisHash"; + } + + #endregion +} + +public partial class ZanoCoinTemplate +{ + #region Overrides of CoinTemplate + + public ZanoCoinTemplate() : base() + { + progpowLightValue = new Lazy(() => + ProgpowFactory.GetProgpow(Symbol, ComponentContext, Hash.ToString().ToLower())); + } + + private readonly Lazy progpowLightValue; + + public IComponentContext ComponentContext { get; [UsedImplicitly] init; } + + public IProgpowLight ProgpowHasher => progpowLightValue.Value; + + public override string GetAlgorithmName() + { + return Hash.ToString(); + } + + #endregion +} + public partial class PoolConfig { /// @@ -308,3 +378,7 @@ public partial class PoolConfig [JsonIgnore] public CoinTemplate Template { get; set; } } + +public partial class CoinMarketCapApi +{ +} diff --git a/src/Miningcore/Configuration/ClusterConfigValidation.cs b/src/Miningcore/Configuration/ClusterConfigValidation.cs index 9129d17c2e..dd20e740a6 100644 --- a/src/Miningcore/Configuration/ClusterConfigValidation.cs +++ b/src/Miningcore/Configuration/ClusterConfigValidation.cs @@ -307,6 +307,10 @@ public partial class PoolConfig { } +public partial class CoinMarketCapApi +{ +} + public partial class ClusterConfig { public void Validate() diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Argon2d16000.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Argon2d16000.cs deleted file mode 100644 index 0ffe3af317..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Argon2d16000.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Miningcore.Contracts; -using Miningcore.Native; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -[Identifier("argon2d16000")] -public unsafe class Argon2d16000 : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.argon2d16000(input, output, (uint) data.Length); - } - } - } -} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Argon2d250.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Argon2d250.cs deleted file mode 100644 index 32e9d92a00..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Argon2d250.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Miningcore.Contracts; -using Miningcore.Native; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -[Identifier("argon2d250")] -public unsafe class Argon2d250 : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.argon2d250(input, output, (uint) data.Length); - } - } - } -} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Argon2d500.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Argon2d500.cs deleted file mode 100644 index fdad67482d..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Argon2d500.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Miningcore.Contracts; -using Miningcore.Native; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -[Identifier("argon2d500")] -public unsafe class Argon2d500 : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.argon2d500(input, output, (uint) data.Length); - } - } - } -} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Blake3.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Blake3.cs index 89fd8d9a60..e8c160cf1c 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Blake3.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Blake3.cs @@ -4,11 +4,11 @@ namespace Miningcore.Crypto.Hashing.Algorithms; [Identifier("blake3")] -public unsafe class Blake3IHash : IHashAlgorithm +public unsafe class Blake3 : IHashAlgorithm { public byte[] dataKey { get; protected set; } = null; - public Blake3IHash(byte[] dataKey = null) + public Blake3(byte[] dataKey = null) { this.dataKey = dataKey; } diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/EvoHash.cs b/src/Miningcore/Crypto/Hashing/Algorithms/EvoHash.cs deleted file mode 100644 index 6673bd10c0..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/EvoHash.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Miningcore.Contracts; -using Miningcore.Native; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -[Identifier("evohash")] -public unsafe class EvoHash : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.evohash(input, output, (uint) data.Length); - } - } - } -} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/FishHash.cs b/src/Miningcore/Crypto/Hashing/Algorithms/FishHash.cs index 2705e38352..1f75d4b6ba 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/FishHash.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/FishHash.cs @@ -1,18 +1,32 @@ +using System; using Miningcore.Contracts; using Miningcore.Native; +using Miningcore.Time; +using NLog; namespace Miningcore.Crypto.Hashing.Algorithms; [Identifier("fishhash")] public unsafe class FishHash : IHashAlgorithm { - private bool enableFishHashPlus = false; + private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); + + public byte fishHashKernel { get; private set; } = 1; private IntPtr handle = IntPtr.Zero; private readonly object genLock = new(); - public FishHash(bool enableFishHashPlus = false, bool fullContext = false, uint threads = 4) + public const byte FishHashKernelV1 = 1; + public const byte FishHashKernelPlus = 2; + public const byte FishHashKernelV2 = 3; + + public FishHash(byte fishHashKernel = 1, bool fullContext = false, uint threads = 4) { - this.enableFishHashPlus = enableFishHashPlus; + Contract.Requires(fishHashKernel >= 1); + + this.fishHashKernel = fishHashKernel; + + var started = DateTime.Now; + logger.Debug(() => $"Generating light cache"); lock(genLock) { @@ -20,6 +34,8 @@ public FishHash(bool enableFishHashPlus = false, bool fullContext = false, uint if(fullContext) Multihash.fishhashPrebuildDataset(this.handle, threads); } + + logger.Debug(() => $"Done generating light cache after {DateTime.Now - started}"); } public void Digest(ReadOnlySpan data, Span result, params object[] extra) @@ -31,7 +47,7 @@ public void Digest(ReadOnlySpan data, Span result, params object[] e { fixed (byte* output = result) { - Multihash.fishhash(output, this.handle, input, (uint) data.Length, this.enableFishHashPlus); + Multihash.fishhash(output, this.handle, input, (uint) data.Length, this.fishHashKernel); } } } diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/FishHashKarlsen.cs b/src/Miningcore/Crypto/Hashing/Algorithms/FishHashKarlsen.cs index 01e6e867e8..15cfe22a00 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/FishHashKarlsen.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/FishHashKarlsen.cs @@ -1,18 +1,28 @@ +using System; using Miningcore.Contracts; using Miningcore.Native; +using Miningcore.Time; +using NLog; namespace Miningcore.Crypto.Hashing.Algorithms; [Identifier("fishhashkarlsen")] public unsafe class FishHashKarlsen : IHashAlgorithm { - private bool enableFishHashPlus = false; + private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); + + public byte fishHashKernel { get; private set; } = 1; private IntPtr handle = IntPtr.Zero; private readonly object genLock = new(); - public FishHashKarlsen(bool enableFishHashPlus = false, bool fullContext = false, uint threads = 4) + public FishHashKarlsen(byte fishHashKernel = 1, bool fullContext = false, uint threads = 4) { - this.enableFishHashPlus = enableFishHashPlus; + Contract.Requires(fishHashKernel >= 1); + + this.fishHashKernel = fishHashKernel; + + var started = DateTime.Now; + logger.Debug(() => $"Generating light cache"); lock(genLock) { @@ -20,6 +30,8 @@ public FishHashKarlsen(bool enableFishHashPlus = false, bool fullContext = false if(fullContext) Multihash.fishhashPrebuildDataset(this.handle, threads); } + + logger.Debug(() => $"Done generating light cache after {DateTime.Now - started}"); } public void Digest(ReadOnlySpan data, Span result, params object[] extra) @@ -27,22 +39,11 @@ public void Digest(ReadOnlySpan data, Span result, params object[] e Contract.Requires(this.handle != IntPtr.Zero); Contract.Requires(result.Length >= 32); - // concat data in byte[64] - Span seedBytes = stackalloc byte[64]; - data.CopyTo(seedBytes); - - var mixHash = new Multihash.Fishhash_hash256(); - - var seed = new Multihash.Fishhash_hash512(); - seed.bytes = seedBytes.ToArray(); - - mixHash = (this.enableFishHashPlus) ? Multihash.fishhashplusKernel(this.handle, ref seed) : Multihash.fishhashKernel(this.handle, ref seed); - - fixed(byte* input = mixHash.bytes) + fixed(byte* input = data) { fixed (byte* output = result) { - Multihash.blake3(input, output, (uint) mixHash.bytes.Length, null, 0); + Multihash.fishhaskarlsen(output, this.handle, input, (uint) data.Length, this.fishHashKernel); } } } diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Flex.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Flex.cs index 9761358585..2d872a7ef3 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Flex.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Flex.cs @@ -1,13 +1,22 @@ +using Miningcore.Contracts; using Miningcore.Native; -using static Miningcore.Native.Cryptonight.Algorithm; namespace Miningcore.Crypto.Hashing.Algorithms; [Identifier("flex")] -public class Flex : IHashAlgorithm + +public unsafe class Flex : IHashAlgorithm { public void Digest(ReadOnlySpan data, Span result, params object[] extra) { - Cryptonight.CryptonightHash(data, result, FLEX_KCN, 0); + Contract.Requires(result.Length >= 32); + + fixed (byte* input = data) + { + fixed (byte* output = result) + { + Multihash.flex(input, output); + } + } } } diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/KeccakC.cs b/src/Miningcore/Crypto/Hashing/Algorithms/KeccakC.cs deleted file mode 100644 index 3b24ce8e15..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/KeccakC.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Miningcore.Contracts; -using Miningcore.Native; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -[Identifier("keccakc")] -public unsafe class KeccakC : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.kezzak(input, output, (uint) data.Length); - } - } - } -} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Kezzak.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Kezzak.cs index 6b038515eb..158c6c5972 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Kezzak.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Kezzak.cs @@ -4,14 +4,29 @@ namespace Miningcore.Crypto.Hashing.Algorithms; -[Identifier("groestl-myriad")] +[Identifier("kezzak")] public unsafe class Kezzak : IHashAlgorithm { public void Digest(ReadOnlySpan data, Span result, params object[] extra) { + Contract.RequiresNonNull(extra); + Contract.Requires(extra.Length > 0); Contract.Requires(result.Length >= 32); - fixed (byte* input = data) + // concat nTime as hex string to data + var nTime = (ulong) extra[0]; + var nTimeHex = nTime.ToString("X").HexToByteArray(); + + Span dataEx = stackalloc byte[data.Length + nTimeHex.Length]; + data.CopyTo(dataEx); + + if(nTimeHex.Length > 0) + { + var dest = dataEx[data.Length..]; + nTimeHex.CopyTo(dest); + } + + fixed (byte* input = dataEx) { fixed (byte* output = result) { diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/MegaBTX.cs b/src/Miningcore/Crypto/Hashing/Algorithms/MegaBTX.cs deleted file mode 100644 index f6fdce53fa..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/MegaBTX.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Miningcore.Contracts; -using Miningcore.Native; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -[Identifier("megabtx")] -public unsafe class MegaBTX : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.megabtx(input, output, (uint) data.Length); - } - } - } -} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Memehash.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Memehash.cs deleted file mode 100644 index 707b58b5ed..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Memehash.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Miningcore.Contracts; -using Miningcore.Native; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -[Identifier("memehash")] -public unsafe class Memehash : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.memehash(input, output, (uint) data.Length); - } - } - } -} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Mike.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Mike.cs index 9a11c0178d..1e4186b9c2 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Mike.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Mike.cs @@ -1,6 +1,8 @@ using Miningcore.Native; using static Miningcore.Native.Cryptonight.Algorithm; + namespace Miningcore.Crypto.Hashing.Algorithms; + [Identifier("mike")] public class Mike : IHashAlgorithm { diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Phi2.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Phi2.cs index 55ebf6c3b4..6289b335e2 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Phi2.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Phi2.cs @@ -1,21 +1,22 @@ using Miningcore.Contracts; using Miningcore.Native; -namespace Miningcore.Crypto.Hashing.Algorithms; -[Identifier("phi2")] -public unsafe class Phi2 : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.phi2(input, output, (uint) data.Length); - } - } - } -} + namespace Miningcore.Crypto.Hashing.Algorithms; + + [Identifier("phi2")] + public unsafe class Phi2 : IHashAlgorithm + { + public void Digest(ReadOnlySpan data, Span result, params object[] extra) + { + Contract.Requires(result.Length >= 32); + + fixed (byte* input = data) + { + fixed (byte* output = result) + { + Multihash.phi2(input, output, (uint) data.Length); + } + } + } + } \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/RinHash.cs b/src/Miningcore/Crypto/Hashing/Algorithms/RinHash.cs deleted file mode 100644 index 33a4051258..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/RinHash.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Security.Cryptography; -using Isopoh.Cryptography.Argon2; -using Miningcore.Contracts; -using SHA3.Net; -using System.Text; -using Blake3; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -/// -/// RinHash: BLAKE3  Argon2d  SHA3-256 -/// -[Identifier("rinhash")] -public unsafe class RinHash : IHashAlgorithm -{ - private static readonly byte[] Salt; - - static RinHash() - { - Salt = Encoding.UTF8.GetBytes("RinCoinSalt"); - } - - public unsafe void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - // 1. BLAKE3 - var hash = Blake3.Hasher.Hash(data); - var blake3 = hash.AsSpanUnsafe().ToArray(); - - // 2. Argon2d - var config = new Argon2Config - { - Type = Argon2Type.DataDependentAddressing, - Version = Argon2Version.Nineteen, - TimeCost = 2, - MemoryCost = 64, // 64 MB - Lanes = 1, - Threads = 1, - Password = blake3, - Salt = Salt, - HashLength = 32 - }; - - var argon2 = new Argon2(config); - var arresult = argon2.Hash(); - - var sha3 = Sha3.Sha3256().ComputeHash(arresult.Buffer); - - sha3.ToArray().CopyTo(result); - } -} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Sha256T.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Sha256T.cs new file mode 100644 index 0000000000..549dd6bbc0 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Sha256T.cs @@ -0,0 +1,23 @@ +using System.Security.Cryptography; +using Miningcore.Contracts; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +/// +/// Sha-256 triple round +/// +[Identifier("sha256t")] +public class Sha256T : IHashAlgorithm +{ + public void Digest(ReadOnlySpan data, Span result, params object[] extra) + { + Contract.Requires(result.Length >= 32); + + using(var hasher = SHA256.Create()) + { + hasher.TryComputeHash(data, result, out _); + hasher.TryComputeHash(result, result, out _); + hasher.TryComputeHash(result, result, out _); + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/X11Gost.cs b/src/Miningcore/Crypto/Hashing/Algorithms/X11Gost.cs deleted file mode 100644 index 6ab3febc7d..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/X11Gost.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Miningcore.Contracts; -using Miningcore.Native; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -[Identifier("x11gost")] -public unsafe class X11Gost : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.x11gost(input, output, (uint) data.Length); - } - } - } -} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/X11KVS.cs b/src/Miningcore/Crypto/Hashing/Algorithms/X11KVS.cs deleted file mode 100644 index e23f8aa850..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/X11KVS.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Miningcore.Contracts; -using Miningcore.Native; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -[Identifier("x11kvs")] -public unsafe class X11KVS : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.x11kvs(input, output, (uint) data.Length); - } - } - } -} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Aurum.cs b/src/Miningcore/Crypto/Hashing/Algorithms/XelisHash.cs similarity index 73% rename from src/Miningcore/Crypto/Hashing/Algorithms/Aurum.cs rename to src/Miningcore/Crypto/Hashing/Algorithms/XelisHash.cs index fda945d861..3055aa567a 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Aurum.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/XelisHash.cs @@ -3,9 +3,8 @@ namespace Miningcore.Crypto.Hashing.Algorithms; -[Identifier("aurum")] - -public unsafe class Aurum : IHashAlgorithm +[Identifier("xelishash")] +public unsafe class XelisHash : IHashAlgorithm { public void Digest(ReadOnlySpan data, Span result, params object[] extra) { @@ -15,8 +14,9 @@ public void Digest(ReadOnlySpan data, Span result, params object[] e { fixed (byte* output = result) { - Multihash.aurum(input, output, (uint) data.Length); + Multihash.xelishash(input, output, (uint) data.Length); } } } } + diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Argon2d1000.cs b/src/Miningcore/Crypto/Hashing/Algorithms/XelisHashV2.cs similarity index 74% rename from src/Miningcore/Crypto/Hashing/Algorithms/Argon2d1000.cs rename to src/Miningcore/Crypto/Hashing/Algorithms/XelisHashV2.cs index 6029b81c33..8161bae48e 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Argon2d1000.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/XelisHashV2.cs @@ -3,8 +3,8 @@ namespace Miningcore.Crypto.Hashing.Algorithms; -[Identifier("argon2d1000")] -public unsafe class Argon2d1000 : IHashAlgorithm +[Identifier("xelishashv2")] +public unsafe class XelisHashV2 : IHashAlgorithm { public void Digest(ReadOnlySpan data, Span result, params object[] extra) { @@ -14,8 +14,9 @@ public void Digest(ReadOnlySpan data, Span result, params object[] e { fixed (byte* output = result) { - Multihash.argon2d1000(input, output, (uint) data.Length); + Multihash.xelishashv2(input, output, (uint) data.Length); } } } } + diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/XelisV2.cs b/src/Miningcore/Crypto/Hashing/Algorithms/XelisV2.cs deleted file mode 100644 index 917ae7e6ed..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/XelisV2.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Miningcore.Contracts; -using Miningcore.Native; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -[Identifier("xelisv2-pepew")] -public unsafe class XelisV2 : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.xelisv2_pepew(input, output, (uint) data.Length); - } - } - } -} - diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/YespowerADVC.cs b/src/Miningcore/Crypto/Hashing/Algorithms/YespowerADVC.cs deleted file mode 100644 index 1344717062..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/YespowerADVC.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Miningcore.Contracts; -using Miningcore.Native; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -[Identifier("yespoweradvc")] -public unsafe class YespowerADVC : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.yespowerADVC(input, output, (uint) data.Length); - } - } - } -} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/YespowerEQPAY.cs b/src/Miningcore/Crypto/Hashing/Algorithms/YespowerEQPAY.cs deleted file mode 100644 index 1adb3dc92c..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/YespowerEQPAY.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Miningcore.Contracts; -using Miningcore.Native; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -[Identifier("yespowereqpay")] -public unsafe class YespowerEQPAY : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.yespowerEQPAY(input, output, (uint) data.Length); - } - } - } -} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/YespowerMGPC.cs b/src/Miningcore/Crypto/Hashing/Algorithms/YespowerMGPC.cs deleted file mode 100644 index e98076b7df..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/YespowerMGPC.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Miningcore.Contracts; -using Miningcore.Native; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -[Identifier("yespowermgpc")] -public unsafe class YespowerMGPC : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.yespowerMGPC(input, output, (uint) data.Length); - } - } - } -} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/yespowerLTNCG.cs b/src/Miningcore/Crypto/Hashing/Algorithms/yespowerLTNCG.cs deleted file mode 100644 index d8abbb6687..0000000000 --- a/src/Miningcore/Crypto/Hashing/Algorithms/yespowerLTNCG.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Miningcore.Contracts; -using Miningcore.Native; - -namespace Miningcore.Crypto.Hashing.Algorithms; - -[Identifier("yespowerltncg")] -public unsafe class YespowerLTNCG : IHashAlgorithm -{ - public void Digest(ReadOnlySpan data, Span result, params object[] extra) - { - Contract.Requires(result.Length >= 32); - - fixed (byte* input = data) - { - fixed (byte* output = result) - { - Multihash.yespowerLTNCG(input, output, (uint) data.Length); - } - } - } -} diff --git a/src/Miningcore/Crypto/Hashing/Progpow/Evrprogpow/Cache.cs b/src/Miningcore/Crypto/Hashing/Progpow/Evrprogpow/Cache.cs deleted file mode 100644 index 45c614cf36..0000000000 --- a/src/Miningcore/Crypto/Hashing/Progpow/Evrprogpow/Cache.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System.Diagnostics; -using Miningcore.Blockchain.Progpow; -using Miningcore.Contracts; -using Miningcore.Extensions; -using Miningcore.Messaging; -using Miningcore.Native; -using Miningcore.Notifications.Messages; -using NLog; - -namespace Miningcore.Crypto.Hashing.Progpow.Evrprogpow; - -[Identifier("evrprogpow")] -public class Cache : IProgpowCache -{ - public Cache(int epoch) - { - Epoch = epoch; - LastUsed = DateTime.Now; - } - - private IntPtr handle = IntPtr.Zero; - private bool isGenerated = false; - private readonly object genLock = new(); - internal static IMessageBus messageBus; - public int Epoch { get; } - public byte[] SeedHash { get; set; } - public DateTime LastUsed { get; set; } - - public void Dispose() - { - if(handle != IntPtr.Zero) - { - EvrProgpow.DestroyContext(handle); - handle = IntPtr.Zero; - } - } - - public async Task GenerateAsync(ILogger logger) - { - await Task.Run(() => - { - lock(genLock) - { - if(!isGenerated) - { - - var started = DateTime.Now; - logger.Debug(() => $"Generating cache for epoch {Epoch}"); - - handle = EvrProgpow.CreateContext(Epoch); - - logger.Debug(() => $"Done generating cache for epoch {Epoch} after {DateTime.Now - started}"); - isGenerated = true; - - // get the seed hash for this epoch - var res = EvrProgpow.calculate_epoch_seed(Epoch); - SeedHash = res.bytes; - logger.Info(() => $"Seed hash for epoch {Epoch} is {SeedHash.ToHexString()}"); - } - } - }); - } - - public unsafe bool Compute(ILogger logger, int blockNumber, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result) - { - Contract.RequiresNonNull(hash); - - var sw = Stopwatch.StartNew(); - - mixDigest = null; - result = null; - - var value = new EvrProgpow.Ethash_result(); - - var inputHash = new EvrProgpow.Ethash_hash256(); - inputHash.bytes = hash; - - fixed(byte* input = hash) - { - value = EvrProgpow.hash(handle, blockNumber, ref inputHash, nonce); - } - - if(value.final_hash.bytes == null) - { - logger.Error(() => $"EvrProgpow.hash returned null"); - return false; - } - - mixDigest = value.mix_hash.bytes; - result = value.final_hash.bytes; - - messageBus?.SendTelemetry("EvrProgpow", TelemetryCategory.Hash, sw.Elapsed, true); - - return true; - } -} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Progpow/Evrprogpow/EvrProgpowLight.cs b/src/Miningcore/Crypto/Hashing/Progpow/Evrprogpow/EvrProgpowLight.cs deleted file mode 100644 index fbb4dae628..0000000000 --- a/src/Miningcore/Crypto/Hashing/Progpow/Evrprogpow/EvrProgpowLight.cs +++ /dev/null @@ -1,87 +0,0 @@ -using Miningcore.Blockchain.Progpow; -using NLog; - -namespace Miningcore.Crypto.Hashing.Progpow.Evrprogpow; - -[Identifier("evrprogpow")] -public class EvrProgpowLight : IProgpowLight -{ - public void Setup(int totalCache, ulong hardForkBlock = 0) - { - this.numCaches = totalCache; - } - - private int numCaches; // Maximum number of caches to keep before eviction (only init, don't modify) - private readonly object cacheLock = new(); - private readonly Dictionary caches = new(); - private Cache future; - public string AlgoName { get; } = "EvrProgpow"; - - public void Dispose() - { - foreach(var value in caches.Values) - value.Dispose(); - } - - public async Task GetCacheAsync(ILogger logger, int block, CancellationToken ct) - { - var epoch = block / EvrmoreConstants.EpochLength; - Cache result; - - lock(cacheLock) - { - if(numCaches == 0) - numCaches = 3; - - if(!caches.TryGetValue(epoch, out result)) - { - // No cached cache, evict the oldest if the cache limit was reached - while(caches.Count >= numCaches) - { - var toEvict = caches.Values.OrderBy(x => x.LastUsed).First(); - var key = caches.First(pair => pair.Value == toEvict).Key; - var epochToEvict = toEvict.Epoch; - - logger.Info(() => $"Evicting cache for epoch {epochToEvict} in favour of epoch {epoch}"); - toEvict.Dispose(); - caches.Remove(key); - } - - // If we have the new cache pre-generated, use that, otherwise create a new one - if(future != null && future.Epoch == epoch) - { - logger.Debug(() => $"Using pre-generated cache for epoch {epoch}"); - - result = future; - future = null; - } - - else - { - logger.Info(() => $"No pre-generated cache available, creating new for epoch {epoch}"); - result = new Cache(epoch); - } - - caches[epoch] = result; - } - - // If we used up the future cache, or need a refresh, regenerate - else if(future == null || future.Epoch <= epoch) - { - logger.Info(() => $"Pre-generating cache for epoch {epoch + 1}"); - future = new Cache(epoch + 1); - -#pragma warning disable 4014 - future.GenerateAsync(logger); -#pragma warning restore 4014 - } - - result.LastUsed = DateTime.Now; - } - - // get/generate current one - await result.GenerateAsync(logger); - - return result; - } -} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Progpow/Meraki/MerakiLight.cs b/src/Miningcore/Crypto/Hashing/Progpow/Meraki/MerakiLight.cs deleted file mode 100644 index a5c8952ade..0000000000 --- a/src/Miningcore/Crypto/Hashing/Progpow/Meraki/MerakiLight.cs +++ /dev/null @@ -1,87 +0,0 @@ -using Miningcore.Blockchain.Progpow; -using NLog; - -namespace Miningcore.Crypto.Hashing.Progpow.Meraki; - -[Identifier("meraki")] -public class MerakiLight : IProgpowLight -{ - public void Setup(int totalCache, ulong hardForkBlock = 0) - { - this.numCaches = totalCache; - } - - private int numCaches; // Maximum number of caches to keep before eviction (only init, don't modify) - private readonly object cacheLock = new(); - private readonly Dictionary caches = new(); - private Cache future; - public string AlgoName { get; } = "Meraki"; - - public void Dispose() - { - foreach(var value in caches.Values) - value.Dispose(); - } - - public async Task GetCacheAsync(ILogger logger, int block, CancellationToken ct) - { - var epoch = block / TelestaiConstants.EpochLength; - Cache result; - - lock(cacheLock) - { - if(numCaches == 0) - numCaches = 3; - - if(!caches.TryGetValue(epoch, out result)) - { - // No cached cache, evict the oldest if the cache limit was reached - while(caches.Count >= numCaches) - { - var toEvict = caches.Values.OrderBy(x => x.LastUsed).First(); - var key = caches.First(pair => pair.Value == toEvict).Key; - var epochToEvict = toEvict.Epoch; - - logger.Info(() => $"Evicting cache for epoch {epochToEvict} in favour of epoch {epoch}"); - toEvict.Dispose(); - caches.Remove(key); - } - - // If we have the new cache pre-generated, use that, otherwise create a new one - if(future != null && future.Epoch == epoch) - { - logger.Debug(() => $"Using pre-generated cache for epoch {epoch}"); - - result = future; - future = null; - } - - else - { - logger.Info(() => $"No pre-generated cache available, creating new for epoch {epoch}"); - result = new Cache(epoch); - } - - caches[epoch] = result; - } - - // If we used up the future cache, or need a refresh, regenerate - else if(future == null || future.Epoch <= epoch) - { - logger.Info(() => $"Pre-generating cache for epoch {epoch + 1}"); - future = new Cache(epoch + 1); - -#pragma warning disable 4014 - future.GenerateAsync(logger, ct); -#pragma warning restore 4014 - } - - result.LastUsed = DateTime.Now; - } - - // get/generate current one - await result.GenerateAsync(logger, ct); - - return result; - } -} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Progpow/Phihash/Cache.cs b/src/Miningcore/Crypto/Hashing/Progpow/Phihash/Cache.cs deleted file mode 100644 index f357829703..0000000000 --- a/src/Miningcore/Crypto/Hashing/Progpow/Phihash/Cache.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Diagnostics; -using Miningcore.Blockchain.Progpow; -using Miningcore.Contracts; -using Miningcore.Extensions; -using Miningcore.Messaging; -using Miningcore.Native; -using Miningcore.Notifications.Messages; -using NLog; - -namespace Miningcore.Crypto.Hashing.Progpow.Phihash; - -[Identifier("phihash")] -public class Cache : IProgpowCache -{ - public Cache(int epoch) - { - Epoch = epoch; - LastUsed = DateTime.Now; - } - - private IntPtr handle = IntPtr.Zero; - private bool isGenerated = false; - private readonly object genLock = new(); - internal static IMessageBus messageBus; - public int Epoch { get; } - public byte[] SeedHash { get; set; } - public DateTime LastUsed { get; set; } - - public void Dispose() - { - if(handle != IntPtr.Zero) - { - PhiHash.DestroyContext(handle); - handle = IntPtr.Zero; - } - } - - public async Task GenerateAsync(ILogger logger, CancellationToken ct) - { - if(handle == IntPtr.Zero) - { - await Task.Run(() => - { - lock(genLock) - { - if(!isGenerated) - { - // re-check after obtaining lock - if(handle != IntPtr.Zero) - return; - - var started = DateTime.Now; - logger.Debug(() => $"Generating cache for epoch {Epoch}"); - - handle = PhiHash.CreateContext(Epoch); - - logger.Debug(() => $"Done generating cache for epoch {Epoch} after {DateTime.Now - started}"); - - // get the seed hash for this epoch - var res = PhiHash.calculate_epoch_seed(Epoch); - SeedHash = res.bytes; - logger.Info(() => $"Seed hash for epoch {Epoch} is {SeedHash.ToHexString()}"); - - isGenerated = true; - } - } - }, ct); - } - } - - public unsafe bool Compute(ILogger logger, int blockNumber, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result) - { - Contract.RequiresNonNull(hash); - - var sw = Stopwatch.StartNew(); - - mixDigest = null; - result = null; - - var value = new PhiHash.Ethash_result(); - - var inputHash = new PhiHash.Ethash_hash256(); - inputHash.bytes = hash; - - fixed(byte* input = hash) - { - value = PhiHash.hash(handle, blockNumber, ref inputHash, nonce); - } - - if(value.final_hash.bytes == null) - { - logger.Error(() => $"PhiHash.hash returned null"); - return false; - } - - mixDigest = value.mix_hash.bytes; - result = value.final_hash.bytes; - - messageBus?.SendTelemetry("Phihash", TelemetryCategory.Hash, sw.Elapsed, true); - - return true; - } -} diff --git a/src/Miningcore/Crypto/Hashing/Progpow/Phihash/PhihashLight.cs b/src/Miningcore/Crypto/Hashing/Progpow/Phihash/PhihashLight.cs deleted file mode 100644 index d1b5c3ee84..0000000000 --- a/src/Miningcore/Crypto/Hashing/Progpow/Phihash/PhihashLight.cs +++ /dev/null @@ -1,87 +0,0 @@ -using Miningcore.Blockchain.Progpow; -using NLog; - -namespace Miningcore.Crypto.Hashing.Progpow.Phihash; - -[Identifier("phihash")] -public class PhihashLight : IProgpowLight -{ - public void Setup(int totalCache, ulong hardForkBlock = 0) - { - this.numCaches = totalCache; - } - - private int numCaches; // Maximum number of caches to keep before eviction (only init, don't modify) - private readonly object cacheLock = new(); - private readonly Dictionary caches = new(); - private Cache future; - public string AlgoName { get; } = "PhiHash"; - - public void Dispose() - { - foreach(var value in caches.Values) - value.Dispose(); - } - - public async Task GetCacheAsync(ILogger logger, int block, CancellationToken ct) - { - var epoch = block / PhicoinConstants.EpochLength; - Cache result; - - lock(cacheLock) - { - if(numCaches == 0) - numCaches = 3; - - if(!caches.TryGetValue(epoch, out result)) - { - // No cached cache, evict the oldest if the cache limit was reached - while(caches.Count >= numCaches) - { - var toEvict = caches.Values.OrderBy(x => x.LastUsed).First(); - var key = caches.First(pair => pair.Value == toEvict).Key; - var epochToEvict = toEvict.Epoch; - - logger.Info(() => $"Evicting cache for epoch {epochToEvict} in favour of epoch {epoch}"); - toEvict.Dispose(); - caches.Remove(key); - } - - // If we have the new cache pre-generated, use that, otherwise create a new one - if(future != null && future.Epoch == epoch) - { - logger.Debug(() => $"Using pre-generated cache for epoch {epoch}"); - - result = future; - future = null; - } - - else - { - logger.Info(() => $"No pre-generated cache available, creating new for epoch {epoch}"); - result = new Cache(epoch); - } - - caches[epoch] = result; - } - - // If we used up the future cache, or need a refresh, regenerate - else if(future == null || future.Epoch <= epoch) - { - logger.Info(() => $"Pre-generating cache for epoch {epoch + 1}"); - future = new Cache(epoch + 1); - -#pragma warning disable 4014 - future.GenerateAsync(logger, ct); -#pragma warning restore 4014 - } - - result.LastUsed = DateTime.Now; - } - - // get/generate current one - await result.GenerateAsync(logger, ct); - - return result; - } -} diff --git a/src/Miningcore/Crypto/Hashing/Progpow/Meraki/Cache.cs b/src/Miningcore/Crypto/Hashing/Progpow/ProgpowZ/Cache.cs similarity index 78% rename from src/Miningcore/Crypto/Hashing/Progpow/Meraki/Cache.cs rename to src/Miningcore/Crypto/Hashing/Progpow/ProgpowZ/Cache.cs index 27cfbacef6..5347a3f662 100644 --- a/src/Miningcore/Crypto/Hashing/Progpow/Meraki/Cache.cs +++ b/src/Miningcore/Crypto/Hashing/Progpow/ProgpowZ/Cache.cs @@ -1,5 +1,5 @@ using System.Diagnostics; -using Miningcore.Blockchain.Progpow; +using Miningcore.Blockchain.Zano; using Miningcore.Contracts; using Miningcore.Extensions; using Miningcore.Messaging; @@ -7,9 +7,9 @@ using Miningcore.Notifications.Messages; using NLog; -namespace Miningcore.Crypto.Hashing.Progpow.Meraki; +namespace Miningcore.Crypto.Hashing.Progpow.ProgpowZ; -[Identifier("meraki")] +[Identifier("progpowz")] public class Cache : IProgpowCache { public Cache(int epoch) @@ -30,7 +30,7 @@ public void Dispose() { if(handle != IntPtr.Zero) { - MerakiPow.DestroyContext(handle); + ProgPowZ.DestroyContext(handle); handle = IntPtr.Zero; } } @@ -52,12 +52,12 @@ await Task.Run(() => var started = DateTime.Now; logger.Debug(() => $"Generating cache for epoch {Epoch}"); - handle = MerakiPow.CreateContext(Epoch); + handle = ProgPowZ.CreateContext(Epoch); logger.Debug(() => $"Done generating cache for epoch {Epoch} after {DateTime.Now - started}"); // get the seed hash for this epoch - var res = MerakiPow.calculate_epoch_seed(Epoch); + var res = ProgPowZ.calculate_epoch_seed(Epoch); SeedHash = res.bytes; logger.Info(() => $"Seed hash for epoch {Epoch} is {SeedHash.ToHexString()}"); @@ -77,26 +77,26 @@ public unsafe bool Compute(ILogger logger, int blockNumber, byte[] hash, ulong n mixDigest = null; result = null; - var value = new MerakiPow.Ethash_result(); + var value = new ProgPowZ.Ethash_result(); - var inputHash = new MerakiPow.Ethash_hash256(); + var inputHash = new ProgPowZ.Ethash_hash256(); inputHash.bytes = hash; fixed(byte* input = hash) { - value = MerakiPow.hash(handle, blockNumber, ref inputHash, nonce); + value = ProgPowZ.hash(handle, blockNumber, ref inputHash, nonce); } if(value.final_hash.bytes == null) { - logger.Error(() => $"Meraki hash returned null"); + logger.Error(() => $"ProgPowZ.hash returned null"); return false; } mixDigest = value.mix_hash.bytes; result = value.final_hash.bytes; - messageBus?.SendTelemetry("Meraki", TelemetryCategory.Hash, sw.Elapsed, true); + messageBus?.SendTelemetry("ProgpowZ", TelemetryCategory.Hash, sw.Elapsed, true); return true; } diff --git a/src/Miningcore/Crypto/Hashing/Progpow/Sccpow/SccpowLight.cs b/src/Miningcore/Crypto/Hashing/Progpow/ProgpowZ/ProgpowZLight.cs similarity index 90% rename from src/Miningcore/Crypto/Hashing/Progpow/Sccpow/SccpowLight.cs rename to src/Miningcore/Crypto/Hashing/Progpow/ProgpowZ/ProgpowZLight.cs index 281f763175..e134d8dcc1 100644 --- a/src/Miningcore/Crypto/Hashing/Progpow/Sccpow/SccpowLight.cs +++ b/src/Miningcore/Crypto/Hashing/Progpow/ProgpowZ/ProgpowZLight.cs @@ -1,10 +1,10 @@ -using Miningcore.Blockchain.Progpow; +using Miningcore.Blockchain.Zano; using NLog; -namespace Miningcore.Crypto.Hashing.Progpow.Sccpow; +namespace Miningcore.Crypto.Hashing.Progpow.ProgpowZ; -[Identifier("sccpow")] -public class SccpowLight : IProgpowLight +[Identifier("progpowz")] +public class ProgpowZLight : IProgpowLight { public void Setup(int totalCache, ulong hardForkBlock = 0) { @@ -15,7 +15,7 @@ public void Setup(int totalCache, ulong hardForkBlock = 0) private readonly object cacheLock = new(); private readonly Dictionary caches = new(); private Cache future; - public string AlgoName { get; } = "FiroPow"; + public string AlgoName { get; } = "ProgPowZ"; public void Dispose() { @@ -25,7 +25,7 @@ public void Dispose() public async Task GetCacheAsync(ILogger logger, int block, CancellationToken ct) { - var epoch = block / SccConstants.EpochLength; + var epoch = block / ZanoConstants.EpochLength; Cache result; lock(cacheLock) diff --git a/src/Miningcore/Crypto/Hashing/Progpow/Sccpow/Cache.cs b/src/Miningcore/Crypto/Hashing/Progpow/Sccpow/Cache.cs deleted file mode 100644 index 8ee999ad62..0000000000 --- a/src/Miningcore/Crypto/Hashing/Progpow/Sccpow/Cache.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Diagnostics; -using Miningcore.Blockchain.Progpow; -using Miningcore.Contracts; -using Miningcore.Extensions; -using Miningcore.Messaging; -using Miningcore.Native; -using Miningcore.Notifications.Messages; -using NLog; - -namespace Miningcore.Crypto.Hashing.Progpow.Sccpow; - -[Identifier("sccpow")] -public class Cache : IProgpowCache -{ - public Cache(int epoch) - { - Epoch = epoch; - LastUsed = DateTime.Now; - } - - private IntPtr handle = IntPtr.Zero; - private bool isGenerated = false; - private readonly object genLock = new(); - internal static IMessageBus messageBus; - public int Epoch { get; } - public byte[] SeedHash { get; set; } - public DateTime LastUsed { get; set; } - - public void Dispose() - { - if(handle != IntPtr.Zero) - { - SccPow.DestroyContext(handle); - handle = IntPtr.Zero; - } - } - - public async Task GenerateAsync(ILogger logger, CancellationToken ct) - { - if(handle == IntPtr.Zero) - { - await Task.Run(() => - { - lock(genLock) - { - if(!isGenerated) - { - // re-check after obtaining lock - if(handle != IntPtr.Zero) - return; - - var started = DateTime.Now; - logger.Debug(() => $"Generating cache for epoch {Epoch}"); - - handle = SccPow.CreateContext(Epoch); - - logger.Debug(() => $"Done generating cache for epoch {Epoch} after {DateTime.Now - started}"); - - // get the seed hash for this epoch - var res = SccPow.calculate_epoch_seed(Epoch); - SeedHash = res.bytes; - logger.Info(() => $"Seed hash for epoch {Epoch} is {SeedHash.ToHexString()}"); - - isGenerated = true; - } - } - }, ct); - } - } - - public unsafe bool Compute(ILogger logger, int blockNumber, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result) - { - Contract.RequiresNonNull(hash); - - var sw = Stopwatch.StartNew(); - - mixDigest = null; - result = null; - - var value = new SccPow.Ethash_result(); - - var inputHash = new SccPow.Ethash_hash256(); - inputHash.bytes = hash; - - fixed(byte* input = hash) - { - value = SccPow.hash(handle, blockNumber, ref inputHash, nonce); - } - - if(value.final_hash.bytes == null) - { - logger.Error(() => $"SccPow.hash returned null"); - return false; - } - - mixDigest = value.mix_hash.bytes; - result = value.final_hash.bytes; - - messageBus?.SendTelemetry("Sccpow", TelemetryCategory.Hash, sw.Elapsed, true); - - return true; - } -} \ No newline at end of file diff --git a/src/Miningcore/JsonRpc/JsonRpcRequest.cs b/src/Miningcore/JsonRpc/JsonRpcRequest.cs index b30a990032..5beb3a486d 100644 --- a/src/Miningcore/JsonRpc/JsonRpcRequest.cs +++ b/src/Miningcore/JsonRpc/JsonRpcRequest.cs @@ -32,7 +32,7 @@ public JsonRpcRequest(string method, T parameters, object id) [JsonProperty("jsonrpc")] public string JsonRpc => "2.0"; - [JsonProperty("method", NullValueHandling = NullValueHandling.Include)] + [JsonProperty("method", NullValueHandling = NullValueHandling.Ignore)] public string Method { get; set; } [JsonProperty("params")] diff --git a/src/Miningcore/JsonRpc/JsonRpcResponse.cs b/src/Miningcore/JsonRpc/JsonRpcResponse.cs index e567cddb09..15a0d2fe1d 100644 --- a/src/Miningcore/JsonRpc/JsonRpcResponse.cs +++ b/src/Miningcore/JsonRpc/JsonRpcResponse.cs @@ -50,7 +50,7 @@ public JsonRpcResponse(JsonRpcError ex, object id, object result) [JsonProperty(PropertyName = "result", NullValueHandling = NullValueHandling.Ignore)] public object Result { get; set; } - [JsonProperty(PropertyName = "error", NullValueHandling = NullValueHandling.Include)] + [JsonProperty(PropertyName = "error", NullValueHandling = NullValueHandling.Ignore)] public JsonRpcError Error { get; set; } [JsonProperty(PropertyName = "id", NullValueHandling = NullValueHandling.Ignore)] diff --git a/src/Miningcore/Mining/PoolBase.cs b/src/Miningcore/Mining/PoolBase.cs index 4390fe29e3..1c4c6926c1 100644 --- a/src/Miningcore/Mining/PoolBase.cs +++ b/src/Miningcore/Mining/PoolBase.cs @@ -53,6 +53,8 @@ protected PoolBase(IComponentContext ctx, this.serializerSettings = serializerSettings; this.cf = cf; + blocksRepo = ctx.Resolve(); + shareRepo = ctx.Resolve(); this.statsRepo = statsRepo; this.mapper = mapper; this.nicehashService = nicehashService; @@ -61,6 +63,8 @@ protected PoolBase(IComponentContext ctx, protected PoolStats poolStats = new(); protected readonly JsonSerializerSettings serializerSettings; protected readonly IConnectionFactory cf; + protected readonly IBlockRepository blocksRepo; + protected readonly IShareRepository shareRepo; protected readonly IStatsRepository statsRepo; protected readonly IMapper mapper; protected readonly NicehashService nicehashService; @@ -69,7 +73,6 @@ protected PoolBase(IComponentContext ctx, protected static readonly TimeSpan maxShareAge = TimeSpan.FromSeconds(6); protected static readonly TimeSpan loginFailureBanTimeout = TimeSpan.FromSeconds(10); protected static readonly Regex regexStaticDiff = new(@";?d=(\d*(\.\d+)?)", RegexOptions.Compiled); - protected static readonly Regex regexStartDiff = new(@";?sd=(\d*(\.\d+)?)", RegexOptions.Compiled); protected const string PasswordControlVarsSeparator = ";"; protected abstract Task SetupJobManager(CancellationToken ct); @@ -96,27 +99,6 @@ protected PoolBase(IComponentContext ctx, return null; } - protected double? GetStartDiffFromPassparts(string[] parts) - { - if(parts == null || parts.Length == 0) - return null; - - foreach(var part in parts) - { - var m = regexStartDiff.Match(part); - - if(m.Success) - { - var str = m.Groups[1].Value.Trim(); - if(double.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out var diff) && - !double.IsNaN(diff) && !double.IsInfinity(diff)) - return diff; - } - } - - return null; - } - protected override void OnConnect(StratumConnection connection, IPEndPoint ipEndPoint) { // setup context @@ -232,6 +214,7 @@ await Parallel.ForEachAsync(connections, ct, async (kvp, _ct) => { if(!_ct.IsCancellationRequested && connection.IsAlive && connection.Context.IsAuthorized) { + await SuspiciousMinerEffortCheck(connection, ct); ZombieCheck(connection); await func(connection, _ct); @@ -247,6 +230,27 @@ await Parallel.ForEachAsync(connections, ct, async (kvp, _ct) => }); } + protected async Task SuspiciousMinerEffortCheck(StratumConnection connection, CancellationToken ct) + { + if(poolConfig.Banning?.Enabled == true && poolConfig.Banning?.MinerEffortPercent.HasValue == true && poolConfig.Banning?.MinerEffortTime.HasValue == true) + { + var lastBlockTime = await cf.Run(con => blocksRepo.GetLastPoolBlockTimeAsync(con, poolConfig.Id, ct)); + DateTime dateStart = (lastBlockTime.HasValue) ? lastBlockTime.Value : connection.Context.Created; + var minerEffort = await cf.Run(con => shareRepo.GetMinerEffortBetweenCreatedAsync(con, poolConfig.Id, connection.Context.Miner, dateStart, clock.Now, ct)); + if(minerEffort.HasValue) + { + logger.Debug(() => $"[{connection.Context.Miner}] Checking effort for worker: {minerEffort.Value}%"); + + if(minerEffort.Value >= poolConfig.Banning.MinerEffortPercent.Value) + { + banManager.Ban(connection.RemoteEndpoint.Address, TimeSpan.FromSeconds(poolConfig.Banning.MinerEffortTime.Value)); + + throw new Exception($"Detected suspicious over-sharing-worker: Current effort over {poolConfig.Banning.MinerEffortPercent.Value}%. Banning worker for {poolConfig.Banning.MinerEffortTime.Value} seconds"); + } + } + } + } + protected void ZombieCheck(StratumConnection connection) { if(poolConfig.ClientConnectionTimeout > 0) diff --git a/src/Miningcore/Mining/PoolStats.cs b/src/Miningcore/Mining/PoolStats.cs index bf278eeecc..45c8b72657 100644 --- a/src/Miningcore/Mining/PoolStats.cs +++ b/src/Miningcore/Mining/PoolStats.cs @@ -4,6 +4,6 @@ public class PoolStats { public DateTime? LastPoolBlockTime { get; set; } public int ConnectedMiners { get; set; } - public double PoolHashrate { get; set; } - public double SharesPerSecond { get; set; } + public ulong PoolHashrate { get; set; } + public int SharesPerSecond { get; set; } } diff --git a/src/Miningcore/Mining/StatsRecorder.cs b/src/Miningcore/Mining/StatsRecorder.cs index 21f57a3ae0..f35b85054a 100644 --- a/src/Miningcore/Mining/StatsRecorder.cs +++ b/src/Miningcore/Mining/StatsRecorder.cs @@ -130,11 +130,12 @@ private async Task UpdatePoolHashratesAsync(CancellationToken ct) // pool hashrate var poolHashesAccumulated = result.Sum(x => x.Sum); var poolHashrate = pool.HashrateFromShares(poolHashesAccumulated, poolHashTimeFrame); - pool.PoolStats.PoolHashrate = poolHashrate; + poolHashrate = Math.Floor(poolHashrate); + pool.PoolStats.PoolHashrate = (ulong) poolHashrate; // pool shares var poolHashesCountAccumulated = result.Sum(x => x.Count); - pool.PoolStats.SharesPerSecond = Math.Round(poolHashesCountAccumulated / poolHashTimeFrame, 3); + pool.PoolStats.SharesPerSecond = (int) (poolHashesCountAccumulated / poolHashTimeFrame); messageBus.NotifyHashrateUpdated(pool.Config.Id, poolHashrate); } @@ -222,6 +223,7 @@ await cf.RunTx(async (con, tx) => // calculate miner/worker stats var minerHashrate = pool.HashrateFromShares(item.Sum, minerHashTimeFrame); + minerHashrate = Math.Floor(minerHashrate); minerTotalHashrate += minerHashrate; stats.Hashrate = minerHashrate; stats.Worker = item.Worker; diff --git a/src/Miningcore/Mining/WorkerContextBase.cs b/src/Miningcore/Mining/WorkerContextBase.cs index 8ec8137e1c..18068437b5 100644 --- a/src/Miningcore/Mining/WorkerContextBase.cs +++ b/src/Miningcore/Mining/WorkerContextBase.cs @@ -33,6 +33,16 @@ public class WorkerContextBase /// public double? PreviousDifficulty { get; set; } + /// + /// Usually a wallet address + /// + public virtual string Miner { get; set; } + + /// + /// Arbitrary worker identififer for miners using multiple rigs + /// + public virtual string Worker { get; set; } + /// /// UserAgent reported by Stratum /// diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index ef4ad81e05..17add33aec 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -42,55 +42,52 @@ - + - all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + - + - - + + - - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/Miningcore/Native/AstroBWTv3.cs b/src/Miningcore/Native/AstroBWTv3.cs new file mode 100644 index 0000000000..49efca79f0 --- /dev/null +++ b/src/Miningcore/Native/AstroBWTv3.cs @@ -0,0 +1,36 @@ +using Miningcore.Contracts; +using System.Diagnostics; +using System.Runtime.InteropServices; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Native; +using Miningcore.Notifications.Messages; + +// ReSharper disable InconsistentNaming + +namespace Miningcore.Native; + +public unsafe class AstroBWTv3 +{ + internal static IMessageBus messageBus; + + [DllImport("libdero", EntryPoint = "astroBWTv3_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void astroBWTv3(byte* input, int inputLength, void* output); + + public void Digest(ReadOnlySpan data, Span result, params object[] extra) + { + Contract.Requires(result.Length >= 32); + + var sw = Stopwatch.StartNew(); + + fixed (byte* input = data) + { + fixed (byte* output = result) + { + astroBWTv3(input, data.Length, output); + + messageBus?.SendTelemetry("AstroBWTv3", TelemetryCategory.Hash, sw.Elapsed, true); + } + } + } +} \ No newline at end of file diff --git a/src/Miningcore/Native/CortexCuckooCycle.cs b/src/Miningcore/Native/CortexCuckooCycle.cs new file mode 100644 index 0000000000..d7a97d7fe7 --- /dev/null +++ b/src/Miningcore/Native/CortexCuckooCycle.cs @@ -0,0 +1,39 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; +using Miningcore.Contracts; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Native; +using Miningcore.Notifications.Messages; +using CC = Miningcore.Blockchain.Ethereum.CortexConstants; + +// ReSharper disable InconsistentNaming + +namespace Miningcore.Native; + +public unsafe class CortexCuckooCycle +{ + internal static IMessageBus messageBus; + + [DllImport("libcortexcuckoocycle", EntryPoint = "cortexcuckoocycle_export", CallingConvention = CallingConvention.Cdecl)] + public static extern int cortexcuckoocycle(byte* header, int inputLength, uint* solution); + + public int Verify(ReadOnlySpan data, ReadOnlySpan result) + { + Contract.Requires(result.Length == CC.CuckarooSolutionSize); + + var sw = Stopwatch.StartNew(); + + fixed (byte* header = data) + { + fixed (uint* solution = result) + { + var res = cortexcuckoocycle(header, data.Length, solution); + + messageBus?.SendTelemetry("CortexCuckooCycle", TelemetryCategory.Hash, sw.Elapsed, true); + + return res; + } + } + } +} \ No newline at end of file diff --git a/src/Miningcore/Native/Cryptonight.cs b/src/Miningcore/Native/Cryptonight.cs index c9854f25d2..a910e5818a 100644 --- a/src/Miningcore/Native/Cryptonight.cs +++ b/src/Miningcore/Native/Cryptonight.cs @@ -63,8 +63,7 @@ public enum Algorithm CN_GR_4 = 0x63120104, // "cn/turtle" GhostRider CN_GR_5 = 0x63120105, // "cn/turtle-lite" GhostRider GHOSTRIDER_RTM = 0x6c150000, // "ghostrider" GhostRider - GHOSTRIDER_MIKE = 0x6c15006d, // "mike" Mike - FLEX_KCN = 0x6c150001, // "flex" Flex + GHOSTRIDER_MIKE = 0x6c15006d, // "mike" Mike // RX_0 = 0x72151200, // "rx/0" RandomX (reference configuration). // RX_WOW = 0x72141177, // "rx/wow" RandomWOW (Wownero). // RX_ARQ = 0x72121061, // "rx/arq" RandomARQ (Arqma). @@ -100,7 +99,6 @@ public enum Algorithm Algorithm.CN_CCX, Algorithm.GHOSTRIDER_RTM, Algorithm.GHOSTRIDER_MIKE, - Algorithm.FLEX_KCN, }; private static readonly HashSet validCryptonightLiteAlgos = new() diff --git a/src/Miningcore/Native/EvrProgpow.cs b/src/Miningcore/Native/EvrProgpow.cs deleted file mode 100644 index 11250ed8ce..0000000000 --- a/src/Miningcore/Native/EvrProgpow.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Runtime.InteropServices; - -// ReSharper disable FieldCanBeMadeReadOnly.Local -// ReSharper disable MemberCanBePrivate.Local -// ReSharper disable InconsistentNaming - -namespace Miningcore.Native; - -public static unsafe class EvrProgpow -{ - [DllImport("libevrprogpow", EntryPoint = "ethash_create_epoch_context", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr CreateContext(int epoch_number); - - [DllImport("libevrprogpow", EntryPoint = "ethash_destroy_epoch_context", CallingConvention = CallingConvention.Cdecl)] - public static extern void DestroyContext(IntPtr context); - - [DllImport("libevrprogpow", EntryPoint = "hash", CallingConvention = CallingConvention.Cdecl)] - public static extern Ethash_result hash(IntPtr context, int block_number, ref Ethash_hash256 header_hash, ulong nonce); - - [DllImport("libevrprogpow", EntryPoint = "ethash_calculate_epoch_seed", CallingConvention = CallingConvention.Cdecl)] - public static extern Ethash_hash256 calculate_epoch_seed(int epoch_number); - - [StructLayout(LayoutKind.Explicit)] - public struct Ethash_hash256 - { - [FieldOffset(0)] - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] bytes;//x32 - } - - [StructLayout(LayoutKind.Sequential)] - public struct Ethash_result - { - public Ethash_hash256 final_hash;//32 - public Ethash_hash256 mix_hash;//32 - } -} diff --git a/src/Miningcore/Native/Meraki.cs b/src/Miningcore/Native/Meraki.cs deleted file mode 100644 index dc3ce1bfef..0000000000 --- a/src/Miningcore/Native/Meraki.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Runtime.InteropServices; - -// ReSharper disable FieldCanBeMadeReadOnly.Local -// ReSharper disable MemberCanBePrivate.Local -// ReSharper disable InconsistentNaming - -namespace Miningcore.Native; - -public static unsafe class MerakiPow -{ - [DllImport("libmeraki", EntryPoint = "ethash_create_epoch_context", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr CreateContext(int epoch_number); - - [DllImport("libmeraki", EntryPoint = "ethash_destroy_epoch_context", CallingConvention = CallingConvention.Cdecl)] - public static extern void DestroyContext(IntPtr context); - - [DllImport("libmeraki", EntryPoint = "hash", CallingConvention = CallingConvention.Cdecl)] - public static extern Ethash_result hash(IntPtr context, int block_number, ref Ethash_hash256 header_hash, ulong nonce); - - [DllImport("libmeraki", EntryPoint = "ethash_calculate_epoch_seed", CallingConvention = CallingConvention.Cdecl)] - public static extern Ethash_hash256 calculate_epoch_seed(int epoch_number); - - [StructLayout(LayoutKind.Explicit)] - public struct Ethash_hash256 - { - [FieldOffset(0)] - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] bytes;//x32 - } - - [StructLayout(LayoutKind.Sequential)] - public struct Ethash_result - { - public Ethash_hash256 final_hash;//32 - public Ethash_hash256 mix_hash;//32 - } -} \ No newline at end of file diff --git a/src/Miningcore/Native/Multihash.cs b/src/Miningcore/Native/Multihash.cs index 91eb9ed67c..ed1efdefc7 100644 --- a/src/Miningcore/Native/Multihash.cs +++ b/src/Miningcore/Native/Multihash.cs @@ -10,9 +10,6 @@ public static unsafe class Multihash [DllImport("libmultihash", EntryPoint = "quark_export", CallingConvention = CallingConvention.Cdecl)] public static extern void quark(byte* input, void* output, uint inputLength); - [DllImport("libmultihash", EntryPoint = "xelisv2_pepew_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void xelisv2_pepew(byte* input, void* output, uint inputLength); - [DllImport("libmultihash", EntryPoint = "sha256csm_export", CallingConvention = CallingConvention.Cdecl)] public static extern void sha256csm(byte* input, void* output, uint inputLength); @@ -21,13 +18,13 @@ public static unsafe class Multihash [DllImport("libmultihash", EntryPoint = "sha3_512_export", CallingConvention = CallingConvention.Cdecl)] public static extern void sha3_512(byte* input, void* output, uint inputLength); - + [DllImport("libmultihash", EntryPoint = "cshake128_export", CallingConvention = CallingConvention.Cdecl)] public static extern void cshake128(byte* input, uint inputLength, byte* name, uint nameLength, byte* custom, uint customLength, void* output, uint outputLength); [DllImport("libmultihash", EntryPoint = "cshake256_export", CallingConvention = CallingConvention.Cdecl)] public static extern void cshake256(byte* input, uint inputLength, byte* name, uint nameLength, byte* custom, uint customLength, void* output, uint outputLength); - + [DllImport("libmultihash", EntryPoint = "shake128_export", CallingConvention = CallingConvention.Cdecl)] public static extern void shake128(byte* input, uint inputLength, void* output, uint outputLength); @@ -45,10 +42,6 @@ public static unsafe class Multihash [DllImport("libmultihash", EntryPoint = "x11_export", CallingConvention = CallingConvention.Cdecl)] public static extern void x11(byte* input, void* output, uint inputLength); - - [DllImport("libmultihash", EntryPoint = "x11kvs_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void x11kvs(byte* input, void* output, uint inputLength); - [DllImport("libmultihash", EntryPoint = "x13_export", CallingConvention = CallingConvention.Cdecl)] public static extern void x13(byte* input, void* output, uint inputLength); @@ -105,7 +98,7 @@ public static unsafe class Multihash [DllImport("libmultihash", EntryPoint = "blake2b_export", CallingConvention = CallingConvention.Cdecl)] public static extern void blake2b(byte* input, void* output, uint inputLength, int outputLength, byte* key, uint keyLength); - + [DllImport("libmultihash", EntryPoint = "blake3_export", CallingConvention = CallingConvention.Cdecl)] public static extern void blake3(byte* input, void* output, uint inputLength, byte* key, uint keyLength); @@ -177,13 +170,10 @@ public static unsafe class Multihash [DllImport("libmultihash", EntryPoint = "sha256dt_export", CallingConvention = CallingConvention.Cdecl)] public static extern void sha256dt(byte* input, void* output); - + [DllImport("libmultihash", EntryPoint = "minotaurx_export", CallingConvention = CallingConvention.Cdecl)] public static extern void minotaurx(byte* input, void* output); - [DllImport("libmultihash", EntryPoint = "memehash_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void memehash(byte* input, void* output, uint inputLength); - [DllImport("libmultihash", EntryPoint = "skydoge_export", CallingConvention = CallingConvention.Cdecl)] public static extern void skydoge(byte* input, void* output, uint inputLength); @@ -202,24 +192,6 @@ public static unsafe class Multihash [DllImport("libmultihash", EntryPoint = "allium_export", CallingConvention = CallingConvention.Cdecl)] public static extern void allium(byte* input, void* output, uint inputLength); - [DllImport("libmultihash", EntryPoint = "argon2d250_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void argon2d250(byte* input, void* output, uint inputLength); - - [DllImport("libmultihash", EntryPoint = "argon2d500_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void argon2d500(byte* input, void* output, uint inputLength); - - [DllImport("libmultihash", EntryPoint = "argon2d1000_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void argon2d1000(byte* input, void* output, uint inputLength); - - [DllImport("libmultihash", EntryPoint = "argon2d16000_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void argon2d16000(byte* input, void* output, uint inputLength); - - [DllImport("libmultihash", EntryPoint = "aurum_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void aurum(byte* input, void* output, uint inputLength); - - [DllImport("libmultihash", EntryPoint = "megabtx_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void megabtx(byte* input, void* output, uint inputLength); - [DllImport("libmultihash", EntryPoint = "cpupower_export", CallingConvention = CallingConvention.Cdecl)] public static extern void cpupower(byte* input, void* output, uint inputLength); @@ -229,61 +201,33 @@ public static unsafe class Multihash [DllImport("libmultihash", EntryPoint = "yespower_export", CallingConvention = CallingConvention.Cdecl)] public static extern void yespower(byte* input, void* output, uint inputLength); - [DllImport("libmultihash", EntryPoint = "yespowerADVC_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void yespowerADVC(byte* input, void* output, uint inputLength); - - [DllImport("libmultihash", EntryPoint = "yespowerEQPAY_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void yespowerEQPAY(byte* input, void* output, uint inputLength); - [DllImport("libmultihash", EntryPoint = "yespowerIC_export", CallingConvention = CallingConvention.Cdecl)] public static extern void yespowerIC(byte* input, void* output, uint inputLength); [DllImport("libmultihash", EntryPoint = "yespowerR16_export", CallingConvention = CallingConvention.Cdecl)] public static extern void yespowerR16(byte* input, void* output, uint inputLength); - [DllImport("libmultihash", EntryPoint = "yespowerLTNCG_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void yespowerLTNCG(byte* input, void* output, uint inputLength); - - [DllImport("libmultihash", EntryPoint = "yespowerMGPC_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void yespowerMGPC(byte* input, void* output, uint inputLength); - [DllImport("libmultihash", EntryPoint = "yespowerTIDE_export", CallingConvention = CallingConvention.Cdecl)] public static extern void yespowerTIDE(byte* input, void* output, uint inputLength); - [DllImport("libmultihash", EntryPoint = "x11gost_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void x11gost(byte* input, void* output, uint inputLength); - - [DllImport("libmultihash", EntryPoint = "evohash_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void evohash(byte* input, void* output, uint inputLength); + [DllImport("libmultihash", EntryPoint = "flex_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void flex(byte* input, void* output); [DllImport("libmultihash", EntryPoint = "fishhash_get_context", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr fishhashGetContext(bool fullContext = false); - [DllImport("libmultihash", EntryPoint = "fishhash_kernel", CallingConvention = CallingConvention.Cdecl)] - public static extern Fishhash_hash256 fishhashKernel(IntPtr context, ref Fishhash_hash512 seed); - - [DllImport("libmultihash", EntryPoint = "fishhashplus_kernel", CallingConvention = CallingConvention.Cdecl)] - public static extern Fishhash_hash256 fishhashplusKernel(IntPtr context, ref Fishhash_hash512 seed); - [DllImport("libmultihash", EntryPoint = "fishhash_prebuild_dataset", CallingConvention = CallingConvention.Cdecl)] public static extern void fishhashPrebuildDataset(IntPtr context, uint number_threads = 1); [DllImport("libmultihash", EntryPoint = "fishhash_hash", CallingConvention = CallingConvention.Cdecl)] - public static extern void fishhash(void* output, IntPtr context, byte* input, uint inputLength, bool enableFishHashPlus = false); - - [StructLayout(LayoutKind.Explicit)] - public struct Fishhash_hash256 - { - [FieldOffset(0)] - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] bytes;//x32 - } - - [StructLayout(LayoutKind.Explicit)] - public struct Fishhash_hash512 - { - [FieldOffset(0)] - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public byte[] bytes;//x64 - } + public static extern void fishhash(void* output, IntPtr context, byte* input, uint inputLength, byte fishHashKernel = 1); + + [DllImport("libmultihash", EntryPoint = "fishhaskarlsen_hash", CallingConvention = CallingConvention.Cdecl)] + public static extern void fishhaskarlsen(void* output, IntPtr context, byte* input, uint inputLength, byte fishHashKernel = 1); + + [DllImport("libmultihash", EntryPoint = "xelis_hash_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void xelishash(byte* input, void* output, uint inputLength); + + [DllImport("libmultihash", EntryPoint = "xelis_hash_v2_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void xelishashv2(byte* input, void* output, uint inputLength); } diff --git a/src/Miningcore/Native/Panthera.cs b/src/Miningcore/Native/Panthera.cs deleted file mode 100644 index 725529cd15..0000000000 --- a/src/Miningcore/Native/Panthera.cs +++ /dev/null @@ -1,312 +0,0 @@ -using System.Collections.Concurrent; -using System.Diagnostics; -using System.Runtime.InteropServices; -using Miningcore.Contracts; -using Miningcore.Extensions; -using Miningcore.Messaging; -using Miningcore.Notifications.Messages; -using NLog; - -// ReSharper disable UnusedMember.Global -// ReSharper disable InconsistentNaming - -namespace Miningcore.Native; - -public static unsafe class Panthera -{ - private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); - internal static IMessageBus messageBus; - - #region VM managment - - internal static readonly Dictionary>>> realms = new(); - private static readonly byte[] empty = new byte[32]; - - #endregion // VM managment - - [DllImport("libpanthera", EntryPoint = "randomx_get_flags", CallingConvention = CallingConvention.Cdecl)] - private static extern RandomX.randomx_flags get_flags(); - - [DllImport("libpanthera", EntryPoint = "randomx_alloc_cache", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr alloc_cache(RandomX.randomx_flags flags); - - [DllImport("libpanthera", EntryPoint = "randomx_init_cache", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr init_cache(IntPtr cache, IntPtr key, int keysize); - - [DllImport("libpanthera", EntryPoint = "randomx_release_cache", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr release_cache(IntPtr cache); - - [DllImport("libpanthera", EntryPoint = "randomx_alloc_dataset", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr alloc_dataset(RandomX.randomx_flags flags); - - [DllImport("libpanthera", EntryPoint = "randomx_dataset_item_count", CallingConvention = CallingConvention.Cdecl)] - private static extern ulong dataset_item_count(); - - [DllImport("libpanthera", EntryPoint = "randomx_init_dataset", CallingConvention = CallingConvention.Cdecl)] - private static extern void init_dataset(IntPtr dataset, IntPtr cache, ulong startItem, ulong itemCount); - - [DllImport("libpanthera", EntryPoint = "randomx_get_dataset_memory", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr get_dataset_memory(IntPtr dataset); - - [DllImport("libpanthera", EntryPoint = "randomx_release_dataset", CallingConvention = CallingConvention.Cdecl)] - private static extern void release_dataset(IntPtr dataset); - - [DllImport("libpanthera", EntryPoint = "randomx_create_vm", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr create_vm(RandomX.randomx_flags flags, IntPtr cache, IntPtr dataset); - - [DllImport("libpanthera", EntryPoint = "randomx_vm_set_cache", CallingConvention = CallingConvention.Cdecl)] - private static extern void vm_set_cache(IntPtr machine, IntPtr cache); - - [DllImport("libpanthera", EntryPoint = "randomx_vm_set_dataset", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr vm_set_dataset(IntPtr machine, IntPtr dataset); - - [DllImport("libpanthera", EntryPoint = "randomx_destroy_vm", CallingConvention = CallingConvention.Cdecl)] - private static extern void destroy_vm(IntPtr machine); - - [DllImport("libpanthera", EntryPoint = "randomx_calculate_hash", CallingConvention = CallingConvention.Cdecl)] - private static extern void calculate_hash(IntPtr machine, byte* input, int inputSize, byte* output, bool b); - - public class GenContext - { - public DateTime LastAccess { get; set; } = DateTime.Now; - public int VmCount { get; init; } - } - - public class RxDataSet : IDisposable - { - private IntPtr dataset = IntPtr.Zero; - - public void Dispose() - { - if(dataset != IntPtr.Zero) - { - release_dataset(dataset); - dataset = IntPtr.Zero; - } - } - - public IntPtr Init(RandomX.randomx_flags flags, IntPtr cache) - { - dataset = alloc_dataset(flags); - - var itemCount = dataset_item_count(); - init_dataset(dataset, cache, 0, itemCount); - - return dataset; - } - } - - public class RxVm : IDisposable - { - private IntPtr cache = IntPtr.Zero; - private IntPtr vm = IntPtr.Zero; - private RxDataSet ds; - - public void Dispose() - { - if(vm != IntPtr.Zero) - { - destroy_vm(vm); - vm = IntPtr.Zero; - } - - ds?.Dispose(); - - if(cache != IntPtr.Zero) - { - release_cache(cache); - cache = IntPtr.Zero; - } - } - - public void Init(ReadOnlySpan key, RandomX.randomx_flags flags) - { - var ds_ptr = IntPtr.Zero; - - // alloc cache - cache = alloc_cache(flags); - - // init cache - fixed(byte* key_ptr = key) - { - init_cache(cache, (IntPtr) key_ptr, key.Length); - } - - // Enable fast-mode? (requires 2GB+ memory per VM) - if((flags & RandomX.randomx_flags.RANDOMX_FLAG_FULL_MEM) != 0) - { - ds = new RxDataSet(); - ds_ptr = ds.Init(flags, cache); - - // cache is no longer needed in fast-mode - release_cache(cache); - cache = IntPtr.Zero; - } - - vm = create_vm(flags, cache, ds_ptr); - } - - public void CalculateHash(ReadOnlySpan data, Span result) - { - fixed (byte* input = data) - { - fixed (byte* output = result) - { - calculate_hash(vm, input, data.Length, output, false); - } - } - } - } - - public static void WithLock(Action action) - { - lock(realms) - { - action(); - } - } - - public static void CreateSeed(string realm, string seedHex, - RandomX.randomx_flags? flagsOverride = null, RandomX.randomx_flags? flagsAdd = null, int vmCount = 1) - { - lock(realms) - { - if(!realms.TryGetValue(realm, out var seeds)) - { - seeds = new Dictionary>>(); - - realms[realm] = seeds; - } - - if(!seeds.TryGetValue(seedHex, out var seed)) - { - var flags = flagsOverride ?? get_flags(); - - if(flagsAdd.HasValue) - flags |= flagsAdd.Value; - - if (vmCount == -1) - vmCount = Environment.ProcessorCount; - - seed = CreateSeed(realm, seedHex, flags, vmCount); - - seeds[seedHex] = seed; - } - } - } - - private static Tuple> CreateSeed(string realm, string seedHex, RandomX.randomx_flags flags, int vmCount) - { - var vms = new BlockingCollection(); - - var seed = new Tuple>(new GenContext - { - VmCount = vmCount - }, vms); - - void createVm(int index) - { - var start = DateTime.Now; - logger.Info(() => $"Creating VM {realm}@{index + 1} [{flags}], hash {seedHex} ..."); - - var vm = new RxVm(); - vm.Init(seedHex.HexToByteArray(), flags); - - vms.Add(vm); - - logger.Info(() => $"Created VM {realm}@{index + 1} in {DateTime.Now - start}"); - }; - - Parallel.For(0, vmCount, createVm); - - return seed; - } - - public static void DeleteSeed(string realm, string seedHex) - { - Tuple> seed; - - lock(realms) - { - if(!realms.TryGetValue(realm, out var seeds)) - return; - - if(!seeds.Remove(seedHex, out seed)) - return; - } - - // dispose all VMs - var (ctx, col) = seed; - var remaining = ctx.VmCount; - - while (remaining > 0) - { - var vm = col.Take(); - - logger.Info($"Disposing VM {ctx.VmCount - remaining} for realm {realm} and key {seedHex}"); - vm.Dispose(); - - remaining--; - } - } - - public static Tuple> GetSeed(string realm, string seedHex) - { - lock(realms) - { - if(!realms.TryGetValue(realm, out var seeds)) - return null; - - if(!seeds.TryGetValue(seedHex, out var seed)) - return null; - - return seed; - } - } - - public static void CalculateHash(string realm, string seedHex, ReadOnlySpan data, Span result) - { - Contract.Requires(result.Length >= 32); - - var sw = Stopwatch.StartNew(); - var success = false; - - var (ctx, seedVms) = GetSeed(realm, seedHex); - - if(ctx != null) - { - RxVm vm = null; - - try - { - // lease a VM - vm = seedVms.Take(); - - vm.CalculateHash(data, result); - - ctx.LastAccess = DateTime.Now; - success = true; - - messageBus?.SendTelemetry("Panthera", TelemetryCategory.Hash, sw.Elapsed, true); - } - - catch(Exception ex) - { - logger.Error(() => ex.Message); - } - - finally - { - // return it - if(vm != null) - seedVms.Add(vm); - } - } - - if(!success) - { - // clear result on failure - empty.CopyTo(result); - } - } -} diff --git a/src/Miningcore/Native/PhiHash.cs b/src/Miningcore/Native/ProgPowZ.cs similarity index 69% rename from src/Miningcore/Native/PhiHash.cs rename to src/Miningcore/Native/ProgPowZ.cs index 6e5edfc115..0ab0fd3226 100644 --- a/src/Miningcore/Native/PhiHash.cs +++ b/src/Miningcore/Native/ProgPowZ.cs @@ -6,18 +6,18 @@ namespace Miningcore.Native; -public static unsafe class PhiHash +public static unsafe class ProgPowZ { - [DllImport("libphihash", EntryPoint = "ethash_create_epoch_context", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libprogpowz", EntryPoint = "ethash_create_epoch_context", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr CreateContext(int epoch_number); - [DllImport("libphihash", EntryPoint = "ethash_destroy_epoch_context", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libprogpowz", EntryPoint = "ethash_destroy_epoch_context", CallingConvention = CallingConvention.Cdecl)] public static extern void DestroyContext(IntPtr context); - [DllImport("libphihash", EntryPoint = "hash", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libprogpowz", EntryPoint = "hash", CallingConvention = CallingConvention.Cdecl)] public static extern Ethash_result hash(IntPtr context, int block_number, ref Ethash_hash256 header_hash, ulong nonce); - [DllImport("libphihash", EntryPoint = "ethash_calculate_epoch_seed", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libprogpowz", EntryPoint = "ethash_calculate_epoch_seed", CallingConvention = CallingConvention.Cdecl)] public static extern Ethash_hash256 calculate_epoch_seed(int epoch_number); [StructLayout(LayoutKind.Explicit)] diff --git a/src/Miningcore/Native/RandomSCASH.cs b/src/Miningcore/Native/RandomSCASH.cs deleted file mode 100644 index 40952aa21c..0000000000 --- a/src/Miningcore/Native/RandomSCASH.cs +++ /dev/null @@ -1,312 +0,0 @@ -using System.Collections.Concurrent; -using System.Diagnostics; -using System.Runtime.InteropServices; -using Miningcore.Contracts; -using Miningcore.Extensions; -using Miningcore.Messaging; -using Miningcore.Notifications.Messages; -using NLog; - -// ReSharper disable UnusedMember.Global -// ReSharper disable InconsistentNaming - -namespace Miningcore.Native; - -public static unsafe class RandomSCASH -{ - private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); - internal static IMessageBus messageBus; - - #region VM managment - - internal static readonly Dictionary>>> realms = new(); - private static readonly byte[] empty = new byte[32]; - - #endregion // VM managment - - [DllImport("librandomscash", EntryPoint = "randomx_get_flags", CallingConvention = CallingConvention.Cdecl)] - private static extern RandomX.randomx_flags get_flags(); - - [DllImport("librandomscash", EntryPoint = "randomx_alloc_cache", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr alloc_cache(RandomX.randomx_flags flags); - - [DllImport("librandomscash", EntryPoint = "randomx_init_cache", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr init_cache(IntPtr cache, IntPtr key, int keysize); - - [DllImport("librandomscash", EntryPoint = "randomx_release_cache", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr release_cache(IntPtr cache); - - [DllImport("librandomscash", EntryPoint = "randomx_alloc_dataset", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr alloc_dataset(RandomX.randomx_flags flags); - - [DllImport("librandomscash", EntryPoint = "randomx_dataset_item_count", CallingConvention = CallingConvention.Cdecl)] - private static extern ulong dataset_item_count(); - - [DllImport("librandomscash", EntryPoint = "randomx_init_dataset", CallingConvention = CallingConvention.Cdecl)] - private static extern void init_dataset(IntPtr dataset, IntPtr cache, ulong startItem, ulong itemCount); - - [DllImport("librandomscash", EntryPoint = "randomx_get_dataset_memory", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr get_dataset_memory(IntPtr dataset); - - [DllImport("librandomscash", EntryPoint = "randomx_release_dataset", CallingConvention = CallingConvention.Cdecl)] - private static extern void release_dataset(IntPtr dataset); - - [DllImport("librandomscash", EntryPoint = "randomx_create_vm", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr create_vm(RandomX.randomx_flags flags, IntPtr cache, IntPtr dataset); - - [DllImport("librandomscash", EntryPoint = "randomx_vm_set_cache", CallingConvention = CallingConvention.Cdecl)] - private static extern void vm_set_cache(IntPtr machine, IntPtr cache); - - [DllImport("librandomscash", EntryPoint = "randomx_vm_set_dataset", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr vm_set_dataset(IntPtr machine, IntPtr dataset); - - [DllImport("librandomscash", EntryPoint = "randomx_destroy_vm", CallingConvention = CallingConvention.Cdecl)] - private static extern void destroy_vm(IntPtr machine); - - [DllImport("librandomscash", EntryPoint = "randomx_calculate_hash", CallingConvention = CallingConvention.Cdecl)] - private static extern void calculate_hash(IntPtr machine, byte* input, int inputSize, byte* output); - - public class GenContext - { - public DateTime LastAccess { get; set; } = DateTime.Now; - public int VmCount { get; init; } - } - - public class RxDataSet : IDisposable - { - private IntPtr dataset = IntPtr.Zero; - - public void Dispose() - { - if(dataset != IntPtr.Zero) - { - release_dataset(dataset); - dataset = IntPtr.Zero; - } - } - - public IntPtr Init(RandomX.randomx_flags flags, IntPtr cache) - { - dataset = alloc_dataset(flags); - - var itemCount = dataset_item_count(); - init_dataset(dataset, cache, 0, itemCount); - - return dataset; - } - } - - public class RxVm : IDisposable - { - private IntPtr cache = IntPtr.Zero; - private IntPtr vm = IntPtr.Zero; - private RxDataSet ds; - - public void Dispose() - { - if(vm != IntPtr.Zero) - { - destroy_vm(vm); - vm = IntPtr.Zero; - } - - ds?.Dispose(); - - if(cache != IntPtr.Zero) - { - release_cache(cache); - cache = IntPtr.Zero; - } - } - - public void Init(ReadOnlySpan key, RandomX.randomx_flags flags) - { - var ds_ptr = IntPtr.Zero; - - // alloc cache - cache = alloc_cache(flags); - - // init cache - fixed(byte* key_ptr = key) - { - init_cache(cache, (IntPtr) key_ptr, key.Length); - } - - // Enable fast-mode? (requires 2GB+ memory per VM) - if((flags & RandomX.randomx_flags.RANDOMX_FLAG_FULL_MEM) != 0) - { - ds = new RxDataSet(); - ds_ptr = ds.Init(flags, cache); - - // cache is no longer needed in fast-mode - release_cache(cache); - cache = IntPtr.Zero; - } - - vm = create_vm(flags, cache, ds_ptr); - } - - public void CalculateHash(ReadOnlySpan data, Span result) - { - fixed (byte* input = data) - { - fixed (byte* output = result) - { - calculate_hash(vm, input, data.Length, output); - } - } - } - } - - public static void WithLock(Action action) - { - lock(realms) - { - action(); - } - } - - public static void CreateSeed(string realm, string seedHex, - RandomX.randomx_flags? flagsOverride = null, RandomX.randomx_flags? flagsAdd = null, int vmCount = 1) - { - lock(realms) - { - if(!realms.TryGetValue(realm, out var seeds)) - { - seeds = new Dictionary>>(); - - realms[realm] = seeds; - } - - if(!seeds.TryGetValue(seedHex, out var seed)) - { - var flags = flagsOverride ?? get_flags(); - - if(flagsAdd.HasValue) - flags |= flagsAdd.Value; - - if (vmCount == -1) - vmCount = Environment.ProcessorCount; - - seed = CreateSeed(realm, seedHex, flags, vmCount); - - seeds[seedHex] = seed; - } - } - } - - private static Tuple> CreateSeed(string realm, string seedHex, RandomX.randomx_flags flags, int vmCount) - { - var vms = new BlockingCollection(); - - var seed = new Tuple>(new GenContext - { - VmCount = vmCount - }, vms); - - void createVm(int index) - { - var start = DateTime.Now; - logger.Info(() => $"Creating VM {realm}@{index + 1} [{flags}], hash {seedHex} ..."); - - var vm = new RxVm(); - vm.Init(seedHex.HexToByteArray(), flags); - - vms.Add(vm); - - logger.Info(() => $"Created VM {realm}@{index + 1} in {DateTime.Now - start}"); - }; - - Parallel.For(0, vmCount, createVm); - - return seed; - } - - public static void DeleteSeed(string realm, string seedHex) - { - Tuple> seed; - - lock(realms) - { - if(!realms.TryGetValue(realm, out var seeds)) - return; - - if(!seeds.Remove(seedHex, out seed)) - return; - } - - // dispose all VMs - var (ctx, col) = seed; - var remaining = ctx.VmCount; - - while (remaining > 0) - { - var vm = col.Take(); - - logger.Info($"Disposing VM {ctx.VmCount - remaining} for realm {realm} and key {seedHex}"); - vm.Dispose(); - - remaining--; - } - } - - public static Tuple> GetSeed(string realm, string seedHex) - { - lock(realms) - { - if(!realms.TryGetValue(realm, out var seeds)) - return null; - - if(!seeds.TryGetValue(seedHex, out var seed)) - return null; - - return seed; - } - } - - public static void CalculateHash(string realm, string seedHex, ReadOnlySpan data, Span result) - { - Contract.Requires(result.Length >= 32); - - var sw = Stopwatch.StartNew(); - var success = false; - - var (ctx, seedVms) = GetSeed(realm, seedHex); - - if(ctx != null) - { - RxVm vm = null; - - try - { - // lease a VM - vm = seedVms.Take(); - - vm.CalculateHash(data, result); - - ctx.LastAccess = DateTime.Now; - success = true; - - messageBus?.SendTelemetry("RandomSCASH", TelemetryCategory.Hash, sw.Elapsed, true); - } - - catch(Exception ex) - { - logger.Error(() => ex.Message); - } - - finally - { - // return it - if(vm != null) - seedVms.Add(vm); - } - } - - if(!success) - { - // clear result on failure - empty.CopyTo(result); - } - } -} diff --git a/src/Miningcore/Native/RandomXEQ.cs b/src/Miningcore/Native/RandomXEQ.cs deleted file mode 100644 index 78f6dd3c81..0000000000 --- a/src/Miningcore/Native/RandomXEQ.cs +++ /dev/null @@ -1,312 +0,0 @@ -using System.Collections.Concurrent; -using System.Diagnostics; -using System.Runtime.InteropServices; -using Miningcore.Contracts; -using Miningcore.Extensions; -using Miningcore.Messaging; -using Miningcore.Notifications.Messages; -using NLog; - -// ReSharper disable UnusedMember.Global -// ReSharper disable InconsistentNaming - -namespace Miningcore.Native; - -public static unsafe class RandomXEQ -{ - private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); - internal static IMessageBus messageBus; - - #region VM managment - - internal static readonly Dictionary>>> realms = new(); - private static readonly byte[] empty = new byte[32]; - - #endregion // VM managment - - [DllImport("librandomxeq", EntryPoint = "randomx_get_flags", CallingConvention = CallingConvention.Cdecl)] - private static extern RandomX.randomx_flags get_flags(); - - [DllImport("librandomxeq", EntryPoint = "randomx_alloc_cache", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr alloc_cache(RandomX.randomx_flags flags); - - [DllImport("librandomxeq", EntryPoint = "randomx_init_cache", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr init_cache(IntPtr cache, IntPtr key, int keysize); - - [DllImport("librandomxeq", EntryPoint = "randomx_release_cache", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr release_cache(IntPtr cache); - - [DllImport("librandomxeq", EntryPoint = "randomx_alloc_dataset", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr alloc_dataset(RandomX.randomx_flags flags); - - [DllImport("librandomxeq", EntryPoint = "randomx_dataset_item_count", CallingConvention = CallingConvention.Cdecl)] - private static extern ulong dataset_item_count(); - - [DllImport("librandomxeq", EntryPoint = "randomx_init_dataset", CallingConvention = CallingConvention.Cdecl)] - private static extern void init_dataset(IntPtr dataset, IntPtr cache, ulong startItem, ulong itemCount); - - [DllImport("librandomxeq", EntryPoint = "randomx_get_dataset_memory", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr get_dataset_memory(IntPtr dataset); - - [DllImport("librandomxeq", EntryPoint = "randomx_release_dataset", CallingConvention = CallingConvention.Cdecl)] - private static extern void release_dataset(IntPtr dataset); - - [DllImport("librandomxeq", EntryPoint = "randomx_create_vm", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr create_vm(RandomX.randomx_flags flags, IntPtr cache, IntPtr dataset); - - [DllImport("librandomxeq", EntryPoint = "randomx_vm_set_cache", CallingConvention = CallingConvention.Cdecl)] - private static extern void vm_set_cache(IntPtr machine, IntPtr cache); - - [DllImport("librandomxeq", EntryPoint = "randomx_vm_set_dataset", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr vm_set_dataset(IntPtr machine, IntPtr dataset); - - [DllImport("librandomxeq", EntryPoint = "randomx_destroy_vm", CallingConvention = CallingConvention.Cdecl)] - private static extern void destroy_vm(IntPtr machine); - - [DllImport("librandomxeq", EntryPoint = "randomx_calculate_hash", CallingConvention = CallingConvention.Cdecl)] - private static extern void calculate_hash(IntPtr machine, byte* input, int inputSize, byte* output); - - public class GenContext - { - public DateTime LastAccess { get; set; } = DateTime.Now; - public int VmCount { get; init; } - } - - public class RxDataSet : IDisposable - { - private IntPtr dataset = IntPtr.Zero; - - public void Dispose() - { - if(dataset != IntPtr.Zero) - { - release_dataset(dataset); - dataset = IntPtr.Zero; - } - } - - public IntPtr Init(RandomX.randomx_flags flags, IntPtr cache) - { - dataset = alloc_dataset(flags); - - var itemCount = dataset_item_count(); - init_dataset(dataset, cache, 0, itemCount); - - return dataset; - } - } - - public class RxVm : IDisposable - { - private IntPtr cache = IntPtr.Zero; - private IntPtr vm = IntPtr.Zero; - private RxDataSet ds; - - public void Dispose() - { - if(vm != IntPtr.Zero) - { - destroy_vm(vm); - vm = IntPtr.Zero; - } - - ds?.Dispose(); - - if(cache != IntPtr.Zero) - { - release_cache(cache); - cache = IntPtr.Zero; - } - } - - public void Init(ReadOnlySpan key, RandomX.randomx_flags flags) - { - var ds_ptr = IntPtr.Zero; - - // alloc cache - cache = alloc_cache(flags); - - // init cache - fixed(byte* key_ptr = key) - { - init_cache(cache, (IntPtr) key_ptr, key.Length); - } - - // Enable fast-mode? (requires 2GB+ memory per VM) - if((flags & RandomX.randomx_flags.RANDOMX_FLAG_FULL_MEM) != 0) - { - ds = new RxDataSet(); - ds_ptr = ds.Init(flags, cache); - - // cache is no longer needed in fast-mode - release_cache(cache); - cache = IntPtr.Zero; - } - - vm = create_vm(flags, cache, ds_ptr); - } - - public void CalculateHash(ReadOnlySpan data, Span result) - { - fixed (byte* input = data) - { - fixed (byte* output = result) - { - calculate_hash(vm, input, data.Length, output); - } - } - } - } - - public static void WithLock(Action action) - { - lock(realms) - { - action(); - } - } - - public static void CreateSeed(string realm, string seedHex, - RandomX.randomx_flags? flagsOverride = null, RandomX.randomx_flags? flagsAdd = null, int vmCount = 1) - { - lock(realms) - { - if(!realms.TryGetValue(realm, out var seeds)) - { - seeds = new Dictionary>>(); - - realms[realm] = seeds; - } - - if(!seeds.TryGetValue(seedHex, out var seed)) - { - var flags = flagsOverride ?? get_flags(); - - if(flagsAdd.HasValue) - flags |= flagsAdd.Value; - - if (vmCount == -1) - vmCount = Environment.ProcessorCount; - - seed = CreateSeed(realm, seedHex, flags, vmCount); - - seeds[seedHex] = seed; - } - } - } - - private static Tuple> CreateSeed(string realm, string seedHex, RandomX.randomx_flags flags, int vmCount) - { - var vms = new BlockingCollection(); - - var seed = new Tuple>(new GenContext - { - VmCount = vmCount - }, vms); - - void createVm(int index) - { - var start = DateTime.Now; - logger.Info(() => $"Creating VM {realm}@{index + 1} [{flags}], hash {seedHex} ..."); - - var vm = new RxVm(); - vm.Init(seedHex.HexToByteArray(), flags); - - vms.Add(vm); - - logger.Info(() => $"Created VM {realm}@{index + 1} in {DateTime.Now - start}"); - }; - - Parallel.For(0, vmCount, createVm); - - return seed; - } - - public static void DeleteSeed(string realm, string seedHex) - { - Tuple> seed; - - lock(realms) - { - if(!realms.TryGetValue(realm, out var seeds)) - return; - - if(!seeds.Remove(seedHex, out seed)) - return; - } - - // dispose all VMs - var (ctx, col) = seed; - var remaining = ctx.VmCount; - - while (remaining > 0) - { - var vm = col.Take(); - - logger.Info($"Disposing VM {ctx.VmCount - remaining} for realm {realm} and key {seedHex}"); - vm.Dispose(); - - remaining--; - } - } - - public static Tuple> GetSeed(string realm, string seedHex) - { - lock(realms) - { - if(!realms.TryGetValue(realm, out var seeds)) - return null; - - if(!seeds.TryGetValue(seedHex, out var seed)) - return null; - - return seed; - } - } - - public static void CalculateHash(string realm, string seedHex, ReadOnlySpan data, Span result) - { - Contract.Requires(result.Length >= 32); - - var sw = Stopwatch.StartNew(); - var success = false; - - var (ctx, seedVms) = GetSeed(realm, seedHex); - - if(ctx != null) - { - RxVm vm = null; - - try - { - // lease a VM - vm = seedVms.Take(); - - vm.CalculateHash(data, result); - - ctx.LastAccess = DateTime.Now; - success = true; - - messageBus?.SendTelemetry("RandomXEQ", TelemetryCategory.Hash, sw.Elapsed, true); - } - - catch(Exception ex) - { - logger.Error(() => ex.Message); - } - - finally - { - // return it - if(vm != null) - seedVms.Add(vm); - } - } - - if(!success) - { - // clear result on failure - empty.CopyTo(result); - } - } -} diff --git a/src/Miningcore/Native/SccPow.cs b/src/Miningcore/Native/SccPow.cs deleted file mode 100644 index ec660d633e..0000000000 --- a/src/Miningcore/Native/SccPow.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Runtime.InteropServices; - -// ReSharper disable FieldCanBeMadeReadOnly.Local -// ReSharper disable MemberCanBePrivate.Local -// ReSharper disable InconsistentNaming - -namespace Miningcore.Native; - -public static unsafe class SccPow -{ - [DllImport("libsccpow", EntryPoint = "ethash_create_epoch_context", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr CreateContext(int epoch_number); - - [DllImport("libsccpow", EntryPoint = "ethash_destroy_epoch_context", CallingConvention = CallingConvention.Cdecl)] - public static extern void DestroyContext(IntPtr context); - - [DllImport("libsccpow", EntryPoint = "hash", CallingConvention = CallingConvention.Cdecl)] - public static extern Ethash_result hash(IntPtr context, int block_number, ref Ethash_hash256 header_hash, ulong nonce); - - [DllImport("libsccpow", EntryPoint = "ethash_calculate_epoch_seed", CallingConvention = CallingConvention.Cdecl)] - public static extern Ethash_hash256 calculate_epoch_seed(int epoch_number); - - [StructLayout(LayoutKind.Explicit)] - public struct Ethash_hash256 - { - [FieldOffset(0)] - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] bytes;//x32 - } - - [StructLayout(LayoutKind.Sequential)] - public struct Ethash_result - { - public Ethash_hash256 final_hash;//32 - public Ethash_hash256 mix_hash;//32 - } -} \ No newline at end of file diff --git a/src/Miningcore/Native/Verushash.cs b/src/Miningcore/Native/Verushash.cs index 0fb10949e1..3851aaf3fd 100644 --- a/src/Miningcore/Native/Verushash.cs +++ b/src/Miningcore/Native/Verushash.cs @@ -11,6 +11,9 @@ public unsafe class Verushash { [DllImport("libverushash", EntryPoint = "verushash2b2_export", CallingConvention = CallingConvention.Cdecl)] public static extern void verushash2b2(byte* input, byte* output, int input_length); + + [DllImport("libverushash", EntryPoint = "verushash2b2o_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void verushash2b2o(byte* input, byte* output, int input_length); [DllImport("libverushash", EntryPoint = "verushash2b1_export", CallingConvention = CallingConvention.Cdecl)] public static extern void verushash2b1(byte* input, byte* output, int input_length); @@ -37,19 +40,23 @@ public void Digest(ReadOnlySpan data, Span result, string version = case VeruscoinConstants.HashVersion2b2: verushash2b2(input, output, data.Length); break; - + + case VeruscoinConstants.HashVersion2b2o: + verushash2b2o(input, output, data.Length); + break; + case VeruscoinConstants.HashVersion2b1: verushash2b1(input, output, data.Length); break; - + case VeruscoinConstants.HashVersion2b: verushash2b(input, output, data.Length); break; - + case VeruscoinConstants.HashVersion2: verushash2(input, output, data.Length); break; - + default: verushash(input, output, data.Length); break; diff --git a/src/Miningcore/Native/Zanonote.cs b/src/Miningcore/Native/Zanonote.cs new file mode 100644 index 0000000000..e0f4bf8e2a --- /dev/null +++ b/src/Miningcore/Native/Zanonote.cs @@ -0,0 +1,151 @@ +using System.Buffers; +using System.Runtime.InteropServices; +using System.Text; +using Miningcore.Contracts; + +namespace Miningcore.Native; + +public static unsafe class ZanonoteBindings +{ + [DllImport("libzanonote", EntryPoint = "convert_blob_export", CallingConvention = CallingConvention.Cdecl)] + private static extern bool convert_blob(byte* input, int inputSize, byte* output, ref int outputSize); + + [DllImport("libzanonote", EntryPoint = "convert_block_export", CallingConvention = CallingConvention.Cdecl)] + private static extern bool convert_block(byte* input, int inputSize, byte* output, ref int outputSize, ulong nonce); + + [DllImport("libzanonote", EntryPoint = "get_blob_id_export", CallingConvention = CallingConvention.Cdecl)] + private static extern bool get_blob_id(byte* input, int inputSize, byte* output); + + [DllImport("libzanonote", EntryPoint = "get_block_id_export", CallingConvention = CallingConvention.Cdecl)] + private static extern bool get_block_id(byte* input, int inputSize, byte* output); + + public static byte[] ConvertBlob(ReadOnlySpan data, int size) + { + Contract.Requires(data.Length > 0); + + fixed (byte* input = data) + { + // provide reasonable large output buffer + var outputBuffer = ArrayPool.Shared.Rent(0x100); + + try + { + var outputBufferLength = outputBuffer.Length; + + var success = false; + fixed (byte* output = outputBuffer) + { + success = convert_blob(input, size, output, ref outputBufferLength); + } + + if(!success) + { + // if we get false, the buffer might have been too small + 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) + { + success = convert_blob(input, size, output, ref outputBufferLength); + } + + if(!success) + return null; // sorry + } + + // build result buffer + var result = new byte[outputBufferLength]; + Buffer.BlockCopy(outputBuffer, 0, result, 0, outputBufferLength); + + return result; + } + + finally + { + ArrayPool.Shared.Return(outputBuffer); + } + } + } + + public static byte[] ConvertBlock(ReadOnlySpan data, int size, ulong nonce) + { + Contract.Requires(data.Length > 0); + + fixed (byte* input = data) + { + // provide reasonable large output buffer + var outputBuffer = ArrayPool.Shared.Rent(0x100); + + try + { + var outputBufferLength = outputBuffer.Length; + + var success = false; + fixed (byte* output = outputBuffer) + { + success = convert_block(input, size, output, ref outputBufferLength, nonce); + } + + if(!success) + { + // if we get false, the buffer might have been too small + 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) + { + success = convert_block(input, size, output, ref outputBufferLength, nonce); + } + + if(!success) + return null; // sorry + } + + // build result buffer + var result = new byte[outputBufferLength]; + Buffer.BlockCopy(outputBuffer, 0, result, 0, outputBufferLength); + + return result; + } + + finally + { + ArrayPool.Shared.Return(outputBuffer); + } + } + } + + public static void GetBlobId(ReadOnlySpan data, Span result) + { + Contract.Requires(result.Length >= 32); + + fixed (byte* input = data) + { + fixed (byte* output = result) + { + get_blob_id(input, data.Length, output); + } + } + } + + public static void GetBlockId(ReadOnlySpan data, Span result) + { + Contract.Requires(result.Length >= 32); + + fixed (byte* input = data) + { + fixed (byte* output = result) + { + get_block_id(input, data.Length, output); + } + } + } +} diff --git a/src/Miningcore/Payments/PaymentSchemes/PPLNSBFPaymentScheme.cs b/src/Miningcore/Payments/PaymentSchemes/PPLNSBFPaymentScheme.cs index c938f89dcc..6e3ee9cafa 100644 --- a/src/Miningcore/Payments/PaymentSchemes/PPLNSBFPaymentScheme.cs +++ b/src/Miningcore/Payments/PaymentSchemes/PPLNSBFPaymentScheme.cs @@ -158,7 +158,7 @@ private async Task LogDiscardedSharesAsync(CancellationToken ct, PoolConfig pool var poolConfig = pool.Config; var payoutConfig = poolConfig.PaymentProcessing.PayoutSchemeConfig; // calculate the block finder reward (% of the block reward) - var blockFinderPercentage = payoutConfig?.ToObject()?.BlockFinderPercentage ?? 10.0m; + var blockFinderPercentage = payoutConfig?.ToObject()?.BlockFinderPercentage ?? 5.0m; var blockFinderReward = blockReward * (blockFinderPercentage / 100); var done = false; var before = block.Created; diff --git a/src/Miningcore/Payments/PayoutManager.cs b/src/Miningcore/Payments/PayoutManager.cs index f616841dd2..cc333d6099 100644 --- a/src/Miningcore/Payments/PayoutManager.cs +++ b/src/Miningcore/Payments/PayoutManager.cs @@ -140,8 +140,9 @@ private static CoinFamily HandleFamilyOverride(CoinFamily family, PoolConfig poo if(equihashTemplate.UseBitcoinPayoutHandler) return CoinFamily.Bitcoin; - break; + break; + case CoinFamily.Progpow: return CoinFamily.Bitcoin; } @@ -168,7 +169,7 @@ await cf.RunTx(async (con, tx) => if(!block.Effort.HasValue) // fill block effort if empty await CalculateBlockEffortAsync(pool, poolConfig, block, handler, ct); - if(!block.MinerEffort.HasValue) // fill block effort if empty + if(!block.MinerEffort.HasValue) // fill block miner effort if empty await CalculateMinerEffortAsync(pool, poolConfig, block, handler, ct); switch(block.Status) @@ -251,20 +252,19 @@ private async Task CalculateBlockEffortAsync(IMiningPool pool, PoolConfig poolCo private async Task CalculateMinerEffortAsync(IMiningPool pool, PoolConfig poolConfig, Block block, IPayoutHandler handler, CancellationToken ct) { - // get share date-range var from = DateTime.MinValue; var to = block.Created; - var miner = block.Miner; + var miner = block.Miner; - // get last block for pool even for "MinerEffort". We use the same method as pool effort because adding miner address in the equation will just create an overlap in the final calculationMore actions - var lastBlock = await cf.Run(con => blockRepo.GetBlockBeforeAsync(con, poolConfig.Id, new[] + // get last block for pool + var lastBlock = await cf.Run(con => blockRepo.GetMinerBlockBeforeAsync(con, poolConfig.Id, miner, new[] { BlockStatus.Confirmed, BlockStatus.Orphaned, BlockStatus.Pending, - }, block.Created)); + }, block.Created, ct)); if(lastBlock != null) from = lastBlock.Created; @@ -273,8 +273,6 @@ private async Task CalculateMinerEffortAsync(IMiningPool pool, PoolConfig poolCo if(block.MinerEffort.HasValue) block.MinerEffort = handler.AdjustBlockEffort(block.MinerEffort.Value); - - } protected override async Task ExecuteAsync(CancellationToken ct) diff --git a/src/Miningcore/Persistence/Model/PoolStats.cs b/src/Miningcore/Persistence/Model/PoolStats.cs index 01c5c848ea..e6f19656e6 100644 --- a/src/Miningcore/Persistence/Model/PoolStats.cs +++ b/src/Miningcore/Persistence/Model/PoolStats.cs @@ -6,13 +6,13 @@ public record PoolStats public string PoolId { get; init; } public int ConnectedMiners { get; init; } - public double PoolHashrate { get; init; } + public float PoolHashrate { get; init; } public double NetworkHashrate { get; init; } public double NetworkDifficulty { get; init; } public DateTime? LastNetworkBlockTime { get; init; } public long BlockHeight { get; init; } public int ConnectedPeers { get; init; } - public double SharesPerSecond { get; init; } + public int SharesPerSecond { get; init; } public DateTime Created { get; init; } } diff --git a/src/Miningcore/Persistence/Model/Projections/MinerStats.cs b/src/Miningcore/Persistence/Model/Projections/MinerStats.cs index e85ff957e4..eb396ed13e 100644 --- a/src/Miningcore/Persistence/Model/Projections/MinerStats.cs +++ b/src/Miningcore/Persistence/Model/Projections/MinerStats.cs @@ -23,4 +23,6 @@ public class MinerStats public DateTime? LastMinerBlockTime { get; set; } public WorkerPerformanceStatsContainer Performance { get; set; } public MinerWorkerPerformanceStats[] PerformanceStats { get; init; } + public long TotalConfirmedBlocks { get; set; } + public long TotalPendingBlocks { get; set; } } diff --git a/src/Miningcore/Persistence/Postgres/Entities/PoolStats.cs b/src/Miningcore/Persistence/Postgres/Entities/PoolStats.cs index 0db4cb32df..7e1121981b 100644 --- a/src/Miningcore/Persistence/Postgres/Entities/PoolStats.cs +++ b/src/Miningcore/Persistence/Postgres/Entities/PoolStats.cs @@ -6,13 +6,13 @@ public class PoolStats public string PoolId { get; set; } public int ConnectedMiners { get; set; } - public double PoolHashrate { get; set; } + public float PoolHashrate { get; set; } public double NetworkHashrate { get; set; } public double NetworkDifficulty { get; set; } public DateTime? LastNetworkBlockTime { get; set; } public long BlockHeight { get; set; } public int ConnectedPeers { get; set; } - public double SharesPerSecond { get; set; } + public int SharesPerSecond { get; set; } public DateTime Created { get; set; } } diff --git a/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs index bdff877409..888a584aa1 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs @@ -19,25 +19,11 @@ public async Task InsertAsync(IDbConnection con, IDbTransaction tx, Block block) { var mapped = mapper.Map(block); - // kaspa effort fix start here - // If the effort is less than 1e-8, multiply it by 4e9 - if (mapped.Effort < 1e-8) - { - mapped.Effort *= 4e9; - } - - // If the minerEffort is less than 1e-8, multiply it by 4e9 - if (mapped.MinerEffort < 1e-8) - { - mapped.MinerEffort *= 4e9; - } - // kaspa effort fix end here - const string query = @"INSERT INTO blocks(poolid, blockheight, networkdifficulty, status, type, transactionconfirmationdata, miner, reward, effort, minereffort, confirmationprogress, source, hash, created) VALUES(@poolid, @blockheight, @networkdifficulty, @status, @type, @transactionconfirmationdata, - @miner, @reward, (SELECT SUM(difficulty / networkdifficulty) FROM shares WHERE poolid = @poolId AND created > (SELECT created FROM blocks WHERE poolid = @poolId ORDER BY created DESC LIMIT 1) AND created < now()), (SELECT SUM(difficulty / networkdifficulty) FROM shares WHERE poolid = @poolId AND miner = @miner AND created > (SELECT created FROM blocks WHERE poolid = @poolId AND miner = @miner ORDER BY created DESC LIMIT 1) AND created < now()), @confirmationprogress, @source, @hash, @created)"; + @miner, @reward, @effort, @minereffort, @confirmationprogress, @source, @hash, @created)"; await con.ExecuteAsync(query, mapped, tx); } @@ -75,16 +61,13 @@ public async Task PageBlocksAsync(IDbConnection con, string poolId, Blo .ToArray(); } - public async Task PageMinerBlocksAsync(IDbConnection con, string poolId, string address, BlockStatus[] status, - int page, int pageSize, CancellationToken ct) + public async Task PageBlocksAsync(IDbConnection con, BlockStatus[] status, int page, int pageSize, CancellationToken ct) { - const string query = @"SELECT * FROM blocks WHERE poolid = @poolid AND status = ANY(@status) AND miner = @address + 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(new CommandDefinition(query, new { - poolId, - address, status = status.Select(x => x.ToString().ToLower()).ToArray(), offset = page * pageSize, pageSize @@ -93,13 +76,16 @@ public async Task PageMinerBlocksAsync(IDbConnection con, string poolId .ToArray(); } - public async Task PageBlocksAsync(IDbConnection con, BlockStatus[] status, int page, int pageSize, CancellationToken ct) + public async Task PageMinerBlocksAsync(IDbConnection con, string poolId, string address, BlockStatus[] status, + int page, int pageSize, CancellationToken ct) { - const string query = @"SELECT * FROM blocks WHERE status = ANY(@status) + const string query = @"SELECT * FROM blocks WHERE poolid = @poolid AND status = ANY(@status) AND miner = @address ORDER BY created DESC OFFSET @offset FETCH NEXT @pageSize ROWS ONLY"; return (await con.QueryAsync(new CommandDefinition(query, new { + poolId, + address, status = status.Select(x => x.ToString().ToLower()).ToArray(), offset = page * pageSize, pageSize @@ -132,10 +118,25 @@ public async Task GetBlockBeforeAsync(IDbConnection con, string poolId, B .FirstOrDefault(); } + public async Task GetMinerBlockBeforeAsync(IDbConnection con, string poolId, string miner, BlockStatus[] status, DateTime before, CancellationToken ct) + { + const string query = @"SELECT * FROM blocks WHERE poolid = @poolid AND miner = @miner AND status = ANY(@status) AND created < @before + ORDER BY created DESC FETCH NEXT 1 ROWS ONLY"; + return (await con.QueryAsync(new CommandDefinition(query, new + { + poolId, + miner, + before, + status = status.Select(x => x.ToString().ToLower()).ToArray() + }, cancellationToken: ct))) + .Select(mapper.Map) + .FirstOrDefault(); + } + public async Task GetBlockBeforeCountAsync(IDbConnection con, string poolId, BlockStatus[] status, DateTime before) { const string query = @"SELECT * FROM blocks WHERE poolid = @poolid AND status = ANY(@status) AND created < @before"; - + return await con.ExecuteScalarAsync(new CommandDefinition(query, new { poolId, @@ -151,6 +152,27 @@ public Task GetPoolBlockCountAsync(IDbConnection con, string poolId, Cance return con.ExecuteScalarAsync(new CommandDefinition(query, new { poolId }, cancellationToken: ct)); } + public Task GetTotalConfirmedBlocksAsync(IDbConnection con, string poolId, CancellationToken ct) + { + const string query = @"SELECT COUNT(*) FROM blocks WHERE poolid = @poolId AND status = 'confirmed'"; + + return con.ExecuteScalarAsync(new CommandDefinition(query, new { poolId }, cancellationToken: ct)); + } + + public Task GetTotalPendingBlocksAsync(IDbConnection con, string poolId, CancellationToken ct) + { + const string query = @"SELECT COUNT(*) FROM blocks WHERE poolid = @poolId AND status = 'pending'"; + + return con.ExecuteScalarAsync(new CommandDefinition(query, new { poolId }, cancellationToken: ct)); + } + + public Task GetLastConfirmedBlockRewardAsync(IDbConnection con, string poolId, CancellationToken ct) + { + const string query = @"SELECT reward FROM blocks WHERE poolid = @poolId AND status = 'confirmed' ORDER BY created DESC LIMIT 1"; + + return con.ExecuteScalarAsync(new CommandDefinition(query, new { poolId }, cancellationToken: ct)); + } + public Task GetMinerBlockCountAsync(IDbConnection con, string poolId, string address, CancellationToken ct) { const string query = @"SELECT COUNT(*) FROM blocks WHERE poolid = @poolId AND miner = @address"; @@ -158,17 +180,17 @@ public Task GetMinerBlockCountAsync(IDbConnection con, string poolId, stri return con.ExecuteScalarAsync(new CommandDefinition(query, new { poolId, address }, cancellationToken: ct)); } - public Task GetLastPoolBlockTimeAsync(IDbConnection con, string poolId) + public Task GetLastPoolBlockTimeAsync(IDbConnection con, string poolId, CancellationToken ct) { const string query = @"SELECT created FROM blocks WHERE poolid = @poolId ORDER BY created DESC LIMIT 1"; - return con.ExecuteScalarAsync(query, new { poolId }); + return con.ExecuteScalarAsync(new CommandDefinition(query, new { poolId }, cancellationToken: ct)); } - public Task GetLastMinerBlockTimeAsync(IDbConnection con, string poolId, string address) + public Task GetLastMinerBlockTimeAsync(IDbConnection con, string poolId, string address, CancellationToken ct) { const string query = @"SELECT created FROM blocks WHERE poolid = @poolId AND miner = @address ORDER BY created DESC LIMIT 1"; - return con.ExecuteScalarAsync(query, new { poolId, address }); + return con.ExecuteScalarAsync(new CommandDefinition(query, new { poolId, address }, cancellationToken: ct)); } public async Task GetBlockByPoolHeightAndTypeAsync(IDbConnection con, string poolId, long height, string type) @@ -176,7 +198,7 @@ public async Task GetBlockByPoolHeightAndTypeAsync(IDbConnection con, str const string query = @"SELECT * FROM blocks WHERE poolid = @poolId AND blockheight = @height AND type = @type"; return (await con.QueryAsync(query, new - { + { poolId, height, type @@ -184,11 +206,11 @@ public async Task GetBlockByPoolHeightAndTypeAsync(IDbConnection con, str .Select(mapper.Map) .FirstOrDefault(); } - + public async Task GetPoolDuplicateBlockCountByPoolHeightNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, BlockStatus[] status) { const string query = @"SELECT COUNT(id) FROM blocks WHERE poolid = @poolId AND blockheight = @height AND status = ANY(@status)"; - + return await con.ExecuteScalarAsync(new CommandDefinition(query, new { poolId, @@ -196,11 +218,11 @@ public async Task GetPoolDuplicateBlockCountByPoolHeightNoTypeAndStatusAsy status = status.Select(x => x.ToString().ToLower()).ToArray() })); } - + public async Task GetPoolDuplicateBlockBeforeCountByPoolHeightNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, BlockStatus[] status, DateTime before) { const string query = @"SELECT COUNT(id) FROM blocks WHERE poolid = @poolId AND blockheight = @height AND status = ANY(@status) AND created < @before"; - + return await con.ExecuteScalarAsync(new CommandDefinition(query, new { poolId, @@ -209,15 +231,43 @@ public async Task GetPoolDuplicateBlockBeforeCountByPoolHeightNoTypeAndSta before })); } - + public async Task GetPoolDuplicateBlockAfterCountByPoolHeightNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, BlockStatus[] status, DateTime after) { const string query = @"SELECT COUNT(id) FROM blocks WHERE poolid = @poolId AND blockheight = @height AND status = ANY(@status) AND created > @after"; + + return await con.ExecuteScalarAsync(new CommandDefinition(query, new + { + poolId, + height, + status = status.Select(x => x.ToString().ToLower()).ToArray(), + after + })); + } + public async Task GetPoolDuplicateBlockBeforeCountByPoolHeightAndHashNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, string hash, BlockStatus[] status, DateTime before) + { + const string query = @"SELECT COUNT(id) FROM blocks WHERE poolid = @poolId AND blockheight = @height AND hash = @hash AND status = ANY(@status) AND created < @before"; + + return await con.ExecuteScalarAsync(new CommandDefinition(query, new + { + poolId, + height, + hash, + status = status.Select(x => x.ToString().ToLower()).ToArray(), + before + })); + } + + public async Task GetPoolDuplicateBlockAfterCountByPoolHeightAndHashNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, string hash, BlockStatus[] status, DateTime after) + { + const string query = @"SELECT COUNT(id) FROM blocks WHERE poolid = @poolId AND blockheight = @height AND hash = @hash AND status = ANY(@status) AND created > @after"; + return await con.ExecuteScalarAsync(new CommandDefinition(query, new { poolId, height, + hash, status = status.Select(x => x.ToString().ToLower()).ToArray(), after })); diff --git a/src/Miningcore/Persistence/Postgres/Repositories/ShareRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/ShareRepository.cs index 1f2113c80f..90e75a07a7 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/ShareRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/ShareRepository.cs @@ -75,18 +75,18 @@ public Task CountSharesByMinerAsync(IDbConnection con, IDbTransaction tx, return con.QuerySingleAsync(new CommandDefinition(query, new { poolId, miner}, tx, cancellationToken: ct)); } - public Task GetEffortBetweenCreatedAsync(IDbConnection con, string poolId, DateTime start, DateTime end) + public Task GetEffortBetweenCreatedAsync(IDbConnection con, string poolId, double shareConst, DateTime start, DateTime end, CancellationToken ct) { - const string query = "SELECT SUM(difficulty / networkdifficulty) FROM shares WHERE poolid = @poolId AND created > @start AND created < @end"; + const string query = "SELECT SUM((difficulty * @shareConst) / networkdifficulty) FROM shares WHERE poolid = @poolId AND created > @start AND created < @end"; - return con.QuerySingleAsync(query, new { poolId, start, end }); + return con.QuerySingleAsync(new CommandDefinition(query, new { poolId, shareConst, start, end }, cancellationToken: ct)); } - public Task GetMinerEffortBetweenCreatedAsync(IDbConnection con, string poolId, string miner, DateTime start, DateTime end) + public Task GetMinerEffortBetweenCreatedAsync(IDbConnection con, string poolId, string miner, DateTime start, DateTime end, CancellationToken ct) { const string query = "SELECT SUM(difficulty / networkdifficulty) FROM shares WHERE poolid = @poolId AND miner = @miner AND created > @start AND created < @end"; - return con.QuerySingleAsync(query, new { poolId, miner, start, end }); + return con.QuerySingleAsync(new CommandDefinition(query, new { poolId, miner, start, end }, cancellationToken: ct)); } public async Task DeleteSharesByMinerAsync(IDbConnection con, IDbTransaction tx, string poolId, string miner, CancellationToken ct) @@ -119,7 +119,7 @@ public async Task DeleteSharesBeforeAsync(IDbConnection con, IDbTransaction tx, public Task GetEffectiveAccumulatedShareDifficultyBetweenAsync(IDbConnection con, string poolId, DateTime start, DateTime end, CancellationToken ct) { - const string query = "SELECT SUM(difficulty / NULLIF(networkdifficulty, 0)) FROM shares WHERE poolid = @poolId AND created > @start AND created <= @end AND networkdifficulty > 0"; + const string query = "SELECT SUM(difficulty / networkdifficulty) FROM shares WHERE poolid = @poolId AND created > @start AND created < @end"; return con.QuerySingleAsync(new CommandDefinition(query, new { poolId, start, end }, cancellationToken: ct)); } diff --git a/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs index cf16d9512b..46e00fa716 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/StatsRepository.cs @@ -320,19 +320,19 @@ public async Task PagePoolMinersByHashrateAsync(I const string query = @"WITH tmp AS ( - SELECT - ms.miner, - AVG(ms.hashrate) AS avg_hashrate, - AVG(ms.sharespersecond) AS avg_sharespersecond, - ROW_NUMBER() OVER(PARTITION BY ms.miner ORDER BY AVG(ms.hashrate) DESC) AS rk - FROM minerstats ms - WHERE ms.poolid = @poolid AND ms.created >= @from - GROUP BY ms.miner + SELECT + ms.miner, + ms.hashrate, + ms.sharespersecond, + ROW_NUMBER() OVER(PARTITION BY ms.miner ORDER BY ms.hashrate DESC) AS rk + FROM (SELECT miner, SUM(hashrate) AS hashrate, SUM(sharespersecond) AS sharespersecond + FROM minerstats + WHERE poolid = @poolid AND created >= @from GROUP BY miner, created) ms ) - SELECT t.miner, t.avg_hashrate AS hashrate, t.avg_sharespersecond AS sharespersecond + SELECT t.miner, t.hashrate, t.sharespersecond FROM tmp t WHERE t.rk = 1 - ORDER BY t.avg_hashrate DESC + ORDER by t.hashrate DESC OFFSET @offset FETCH NEXT @pageSize ROWS ONLY"; return (await con.QueryAsync(new CommandDefinition(query, @@ -354,4 +354,18 @@ public Task DeleteMinerStatsBeforeAsync(IDbConnection con, DateTime date, C return con.ExecuteAsync(new CommandDefinition(query, new { date }, cancellationToken: ct)); } + + public Task GetMinerTotalConfirmedBlocksAsync(IDbConnection con, string poolId, string miner, CancellationToken ct) + { + const string query = @"SELECT COUNT(*) FROM blocks WHERE poolid = @poolId AND miner = @miner AND status = 'confirmed'"; + + return con.ExecuteScalarAsync(new CommandDefinition(query, new { poolId, miner }, cancellationToken: ct)); + } + + public Task GetMinerTotalPendingBlocksAsync(IDbConnection con, string poolId, string miner, CancellationToken ct) + { + const string query = @"SELECT COUNT(*) FROM blocks WHERE poolid = @poolId AND miner = @miner AND status = 'pending'"; + + return con.ExecuteScalarAsync(new CommandDefinition(query, new { poolId, miner }, cancellationToken: ct)); + } } diff --git a/src/Miningcore/Persistence/Postgres/Scripts/add_minereffort.sql b/src/Miningcore/Persistence/Postgres/Scripts/add_minereffort.sql index 88a35d3ac1..fb306ae025 100644 --- a/src/Miningcore/Persistence/Postgres/Scripts/add_minereffort.sql +++ b/src/Miningcore/Persistence/Postgres/Scripts/add_minereffort.sql @@ -1,2 +1 @@ -\c miningcore -ALTER TABLE blocks ADD COLUMN minereffort FLOAT NULL; +ALTER TABLE blocks ADD COLUMN IF NOT EXISTS minereffort FLOAT NULL; \ No newline at end of file diff --git a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql index 090e9163ab..847644760b 100644 --- a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql +++ b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql @@ -28,7 +28,7 @@ CREATE TABLE blocks type TEXT NULL, confirmationprogress FLOAT NOT NULL DEFAULT 0, effort FLOAT NULL, - minereffort FLOAT NULL, + minereffort FLOAT NULL, transactionconfirmationdata TEXT NOT NULL, miner TEXT NULL, reward decimal(28,12) NULL, diff --git a/src/Miningcore/Persistence/Repositories/IBlockRepository.cs b/src/Miningcore/Persistence/Repositories/IBlockRepository.cs index 42829ffa83..638617d073 100644 --- a/src/Miningcore/Persistence/Repositories/IBlockRepository.cs +++ b/src/Miningcore/Persistence/Repositories/IBlockRepository.cs @@ -14,13 +14,19 @@ public interface IBlockRepository Task PageMinerBlocksAsync(IDbConnection con, string poolId, string address, BlockStatus[] status, int page, int pageSize, CancellationToken ct); Task GetPendingBlocksForPoolAsync(IDbConnection con, string poolId); Task GetBlockBeforeAsync(IDbConnection con, string poolId, BlockStatus[] status, DateTime before); + Task GetMinerBlockBeforeAsync(IDbConnection con, string poolId, string miner, BlockStatus[] status, DateTime before, CancellationToken ct); Task GetBlockBeforeCountAsync(IDbConnection con, string poolId, BlockStatus[] status, DateTime before); Task GetPoolBlockCountAsync(IDbConnection con, string poolId, CancellationToken ct); + Task GetTotalConfirmedBlocksAsync(IDbConnection con, string poolId, CancellationToken ct); + Task GetTotalPendingBlocksAsync(IDbConnection con, string poolId, CancellationToken ct); + Task GetLastConfirmedBlockRewardAsync(IDbConnection con, string poolId, CancellationToken ct); + Task GetLastMinerBlockTimeAsync(IDbConnection con, string poolId, string address, CancellationToken ct); Task GetMinerBlockCountAsync(IDbConnection con, string poolId, string address, CancellationToken ct); - Task GetLastPoolBlockTimeAsync(IDbConnection con, string poolId); - Task GetLastMinerBlockTimeAsync(IDbConnection con, string poolId, string address); + Task GetLastPoolBlockTimeAsync(IDbConnection con, string poolId, CancellationToken ct); Task GetBlockByPoolHeightAndTypeAsync(IDbConnection con, string poolId, long height, string type); Task GetPoolDuplicateBlockCountByPoolHeightNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, BlockStatus[] status); Task GetPoolDuplicateBlockBeforeCountByPoolHeightNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, BlockStatus[] status, DateTime before); Task GetPoolDuplicateBlockAfterCountByPoolHeightNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, BlockStatus[] status, DateTime after); + Task GetPoolDuplicateBlockBeforeCountByPoolHeightAndHashNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, string hash, BlockStatus[] status, DateTime before); + Task GetPoolDuplicateBlockAfterCountByPoolHeightAndHashNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, string hash, BlockStatus[] status, DateTime after); } diff --git a/src/Miningcore/Persistence/Repositories/IShareRepository.cs b/src/Miningcore/Persistence/Repositories/IShareRepository.cs index 01e5244658..ff43d8f1d3 100644 --- a/src/Miningcore/Persistence/Repositories/IShareRepository.cs +++ b/src/Miningcore/Persistence/Repositories/IShareRepository.cs @@ -15,8 +15,8 @@ public interface IShareRepository Task GetAccumulatedShareDifficultyBetweenAsync(IDbConnection con, string poolId, DateTime start, DateTime end, CancellationToken ct); Task GetMinerShareDifficultyBetweenAsync(IDbConnection con, string poolId, string miner, DateTime start, DateTime end, CancellationToken ct); Task GetEffectiveAccumulatedShareDifficultyBetweenAsync(IDbConnection con, string poolId, DateTime start, DateTime end, CancellationToken ct); - Task GetEffortBetweenCreatedAsync(IDbConnection con, string poolId, DateTime start, DateTime end); - Task GetMinerEffortBetweenCreatedAsync(IDbConnection con, string poolId, string miner,DateTime start, DateTime end); + Task GetEffortBetweenCreatedAsync(IDbConnection con, string poolId, double shareConst, DateTime start, DateTime end, CancellationToken ct); + Task GetMinerEffortBetweenCreatedAsync(IDbConnection con, string poolId, string miner,DateTime start, DateTime end, CancellationToken ct); Task GetHashAccumulationBetweenAsync(IDbConnection con, string poolId, DateTime start, DateTime end, CancellationToken ct); Task GetRecentyUsedIpAddressesAsync(IDbConnection con, IDbTransaction tx, string poolId, string miner, CancellationToken ct); diff --git a/src/Miningcore/Persistence/Repositories/IStatsRepository.cs b/src/Miningcore/Persistence/Repositories/IStatsRepository.cs index 02c6e4e508..a5bbc81e8f 100644 --- a/src/Miningcore/Persistence/Repositories/IStatsRepository.cs +++ b/src/Miningcore/Persistence/Repositories/IStatsRepository.cs @@ -27,4 +27,6 @@ Task GetMinerPerformanceBetweenDailyAsync(IDb Task DeletePoolStatsBeforeAsync(IDbConnection con, DateTime date, CancellationToken ct); Task DeleteMinerStatsBeforeAsync(IDbConnection con, DateTime date, CancellationToken ct); + Task GetMinerTotalConfirmedBlocksAsync(IDbConnection con, string poolId, string miner, CancellationToken ct); + Task GetMinerTotalPendingBlocksAsync(IDbConnection con, string poolId, string miner, CancellationToken ct); } diff --git a/src/Miningcore/Program.cs b/src/Miningcore/Program.cs index c9513a9ada..b2eba598d4 100644 --- a/src/Miningcore/Program.cs +++ b/src/Miningcore/Program.cs @@ -31,13 +31,10 @@ using Miningcore.Crypto.Hashing.Ethash.Ethash; using Miningcore.Crypto.Hashing.Ethash.Ethashb3; using Miningcore.Crypto.Hashing.Ethash.Ubqhash; -using Miningcore.Crypto.Hashing.Progpow.Evrprogpow; using Miningcore.Crypto.Hashing.Progpow.Firopow; using Miningcore.Crypto.Hashing.Progpow.Kawpow; using Miningcore.Crypto.Hashing.Progpow.Meowpow; -using Miningcore.Crypto.Hashing.Progpow.Meraki; -using Miningcore.Crypto.Hashing.Progpow.Phihash; -using Miningcore.Crypto.Hashing.Progpow.Sccpow; +using Miningcore.Crypto.Hashing.Progpow.ProgpowZ; using Miningcore.Extensions; using Miningcore.Messaging; using Miningcore.Mining; @@ -66,6 +63,8 @@ using ILogger = NLog.ILogger; using LogLevel = Microsoft.Extensions.Logging.LogLevel; using static Miningcore.Util.ActionUtils; +using Miningcore.CoinMarketCap; +using System.Net.Http.Headers; // ReSharper disable AssignNullToNotNullAttribute // ReSharper disable PossibleNullReferenceException @@ -203,6 +202,12 @@ public static async Task Main(string[] args) services.AddResponseCompression(); services.AddCors(); services.AddWebSocketManager(); + services.AddHttpClient(CoinMarketCapConstants.HttpKeyword, (client) => + { + client.DefaultRequestHeaders.Add("X-CMC_PRO_API_KEY", clusterConfig.CoinMarketCapApi.Key); + client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + client.BaseAddress = new Uri("https://pro-api.coinmarketcap.com/v2/"); + }); }) .UseKestrel(options => { @@ -631,7 +636,7 @@ private static void Logo() ██║╚██╔╝██║██║██║╚██╗██║██║██║╚██╗██║██║ ██║██║ ██║ ██║██╔══██╗██╔══╝ ██║ ╚═╝ ██║██║██║ ╚████║██║██║ ╚████║╚██████╔╝╚██████╗╚██████╔╝██║ ██║███████╗ "); - Console.WriteLine(" https://github.com/Kudaraidee/miningcore\n"); + Console.WriteLine(" https://github.com/blackmennewstyle/miningcore\n"); Console.WriteLine(" Donate to one of these addresses to support the project:\n"); Console.WriteLine(" ETH - 0xbC059e88A4dD11c2E882Fc6B83F8Ec12E4CCCFad"); Console.WriteLine(" BTC - 16xvkGfG9nrJSKKo5nGWphP8w4hr2ZzVuw"); @@ -641,7 +646,11 @@ private static void Logo() Console.WriteLine(" CCX - ccx7S4B3gBeH1SGWCfqZp3NM7Vavg7H3S8ovJn8fU4bwC4vU7ChWfHtbNzifhrpbJ74bMDxj4KZFTcznTfsucCEg1Kgv7zbNgs"); Console.WriteLine(" FIRO - a5AsoTSkfPHQ3SUmR6binG1XW7oQQoFNU1"); Console.WriteLine(" ERGO - 9gYyuZzaSw3TiCtUkSRuS3XVDUv41EFs3dtNCFGqiEwHqpb7gkF"); + Console.WriteLine(" WART - 7795fc0fe93e7e4e232a212f00bdc8885c580a5666d39a0d"); Console.WriteLine(" XMR - 483zaHtMRfM7rw1dXgebhWaRR8QLgAF6w4BomAV319FVVHfdbYTLVuBRc4pQgRAnRpfy6CXvvwngK4Lo3mRKE29RRx3Jb5c"); + Console.WriteLine(" XEL - xel:ajnsfv065qusndt0hfsngecrnf5690drmqmc0uq0etlx8zjlcyzqq2slgvt"); + Console.WriteLine(" CTXC - 0xbb60200d5151a4a0f9a75014e04cf61a0a9f0daf"); + Console.WriteLine(" ZANO - ZxDKT1aqiEXPA5cDADtYEfMR1oXsRd68bby4nzUvVmnjHzzrfvjwhNdQ9yiWNeGutzg9LZdwsbP2FGB1gNpZXiYY1fCfpw33c"); Console.WriteLine(); } @@ -819,24 +828,12 @@ private static async Task PreFlightChecks(IServiceProvider services) // Configure RandomARQ RandomARQ.messageBus = messageBus; - // Configure RandomSCASH - RandomSCASH.messageBus = messageBus; - - // Configure RandomXEQ - RandomXEQ.messageBus = messageBus; - - // Configure Panthera - Panthera.messageBus = messageBus; - // Configure NexaPow Miningcore.Crypto.Hashing.Algorithms.NexaPow.messageBus = messageBus; // Configure BeamHash BeamHash.messageBus = messageBus; - // Configure Evrprogpow - Miningcore.Crypto.Hashing.Progpow.Evrprogpow.Cache.messageBus = messageBus; - // Configure FiroPow Miningcore.Crypto.Hashing.Progpow.Firopow.Cache.messageBus = messageBus; @@ -846,15 +843,8 @@ private static async Task PreFlightChecks(IServiceProvider services) // Configure Meowpow Miningcore.Crypto.Hashing.Progpow.Meowpow.Cache.messageBus = messageBus; - // Configure Meraki - Miningcore.Crypto.Hashing.Progpow.Meraki.Cache.messageBus = messageBus; - - // Configure Phihash - Miningcore.Crypto.Hashing.Progpow.Phihash.Cache.messageBus = messageBus; - - // Configure Sccpow - Miningcore.Crypto.Hashing.Progpow.Sccpow.Cache.messageBus = messageBus; - + // Configure ProgpowZ + Miningcore.Crypto.Hashing.Progpow.ProgpowZ.Cache.messageBus = messageBus; } private static async Task ConfigurePostgresCompatibilityOptions(IServiceProvider services) diff --git a/src/Miningcore/Rpc/RpcClient.cs b/src/Miningcore/Rpc/RpcClient.cs index 057c1fe32c..3d0486894a 100644 --- a/src/Miningcore/Rpc/RpcClient.cs +++ b/src/Miningcore/Rpc/RpcClient.cs @@ -280,7 +280,7 @@ private IObservable WebsocketSubscribeEndpoint(ILogger logger, Cancellat var json = JsonConvert.SerializeObject(request, payloadJsonSerializerSettings); var requestData = new ArraySegment(Encoding.UTF8.GetBytes(json)); - logger.Debug(() => $"Sending WebSocket subscription request to {uri}"); + logger.Debug(() => $"Sending WebSocket subscription request `{json}` to {uri}"); await client.SendAsync(requestData, WebSocketMessageType.Text, true, cts.Token); // stream response diff --git a/src/Miningcore/build-libs-linux.sh b/src/Miningcore/build-libs-linux.sh index 79981e6d2e..87154d32c5 100755 --- a/src/Miningcore/build-libs-linux.sh +++ b/src/Miningcore/build-libs-linux.sh @@ -2,6 +2,9 @@ OutDir=$1 +export UNAME_S=$(uname -s) +export UNAME_P=$(uname -m || uname -p) + AES=$(../Native/check_cpu.sh aes && echo -maes || echo) SSE2=$(../Native/check_cpu.sh sse2 && echo -msse2 || echo) SSE3=$(../Native/check_cpu.sh sse3 && echo -msse3 || echo) @@ -29,7 +32,6 @@ export HAVE_FEATURE="$HAVE_AES $HAVE_SSE2 $HAVE_SSE3 $HAVE_SSSE3 $HAVE_PCLMUL $H (cd ../Native/libetchash && make clean && make) && mv ../Native/libetchash/libetchash.so "$OutDir" (cd ../Native/libethhash && make clean && make) && mv ../Native/libethhash/libethhash.so "$OutDir" (cd ../Native/libethhashb3 && make -j clean && make -j) && mv ../Native/libethhashb3/libethhashb3.so "$OutDir" -(cd ../Native/libevrprogpow && make clean && make) && mv ../Native/libevrprogpow/libevrprogpow.so "$OutDir" (cd ../Native/libubqhash && make clean && make) && mv ../Native/libubqhash/libubqhash.so "$OutDir" (cd ../Native/libcryptonote && make clean && make) && mv ../Native/libcryptonote/libcryptonote.so "$OutDir" (cd ../Native/libcryptonight && make clean && make) && mv ../Native/libcryptonight/libcryptonight.so "$OutDir" @@ -37,13 +39,11 @@ export HAVE_FEATURE="$HAVE_AES $HAVE_SSE2 $HAVE_SSE3 $HAVE_SSSE3 $HAVE_PCLMUL $H (cd ../Native/libfiropow && make clean && make) && mv ../Native/libfiropow/libfiropow.so "$OutDir" (cd ../Native/libkawpow && make clean && make) && mv ../Native/libkawpow/libkawpow.so "$OutDir" (cd ../Native/libmeowpow && make clean && make) && mv ../Native/libmeowpow/libmeowpow.so "$OutDir" -(cd ../Native/libsccpow && make clean && make) && mv ../Native/libsccpow/libsccpow.so "$OutDir" -(cd ../Native/libmeraki && make clean && make) && mv ../Native/libmeraki/libmeraki.so "$OutDir" -(cd ../Native/libphihash && make clean && make) && mv ../Native/libphihash/libphihash.so "$OutDir" +(cd ../Native/libdero && make clean && make) && mv ../Native/libdero/libdero.so "$OutDir" +(cd ../Native/libcortexcuckoocycle && make clean && make) && mv ../Native/libcortexcuckoocycle/libcortexcuckoocycle.so "$OutDir" +(cd ../Native/libprogpowz && make clean && make) && mv ../Native/libprogpowz/libprogpowz.so "$OutDir" +(cd ../Native/libzanonote && make clean && make) && mv ../Native/libzanonote/libzanonote.so "$OutDir" ((cd /tmp && rm -rf secp256k1 && git clone https://github.com/bitcoin-ABC/secp256k1 && cd secp256k1 && git checkout 04fabb44590c10a19e35f044d11eb5058aac65b2 && mkdir build && cd build && cmake -GNinja .. -DCMAKE_C_FLAGS=-fPIC -DSECP256K1_ENABLE_MODULE_RECOVERY=OFF -DSECP256K1_ENABLE_COVERAGE=OFF -DSECP256K1_ENABLE_MODULE_SCHNORR=ON && ninja) && (cd ../Native/libnexapow && cp /tmp/secp256k1/build/libsecp256k1.a . && make clean && make) && mv ../Native/libnexapow/libnexapow.so "$OutDir") -((cd /tmp && rm -rf RandomX && git clone https://github.com/tevador/RandomX && cd RandomX && git checkout tags/v1.1.10 && mkdir build && cd build && cmake -DARCH=native .. && make) && (cd ../Native/librandomx && cp /tmp/RandomX/build/librandomx.a . && make clean && make) && mv ../Native/librandomx/librandomx.so "$OutDir") -((cd /tmp && rm -rf RandomARQ && git clone https://github.com/arqma/RandomARQ && cd RandomARQ && git checkout 14850620439045b319fa6398f5a164715c4a66ce && mkdir build && cd build && cmake -DARCH=native .. && make) && (cd ../Native/librandomarq && cp /tmp/RandomARQ/build/librandomx.a . && make clean && make) && mv ../Native/librandomarq/librandomarq.so "$OutDir") -((cd /tmp && rm -rf RandomSCASH && git clone https://github.com/scashnetwork/RandomX RandomSCASH && cd RandomSCASH && mkdir build && cd build && cmake -DARCH=native .. && make) && (cd ../Native/librandomscash && cp /tmp/RandomSCASH/build/librandomx.a . && make clean && make) && mv ../Native/librandomscash/librandomscash.so "$OutDir") -((cd /tmp && rm -rf RandomXEQ && git clone https://github.com/EquilibriaCC/RandomXEQ && cd RandomXEQ && mkdir build && cd build && cmake -DARCH=native .. && make) && (cd ../Native/librandomxeq && cp /tmp/RandomXEQ/build/librandomx.a . && make clean && make) && mv ../Native/librandomxeq/librandomxeq.so "$OutDir") -((cd /tmp && rm -rf Panthera && git clone https://github.com/scala-network/Panthera && cd Panthera && mkdir build && cd build && cmake -DARCH=native .. && make) && (cd ../Native/libpanthera && cp /tmp/Panthera/build/librandomx.a . && make clean && make) && mv ../Native/libpanthera/libpanthera.so "$OutDir") +((cd /tmp && rm -rf RandomX && git clone https://github.com/tevador/RandomX && cd RandomX && git checkout tags/v1.2.1 && mkdir build && cd build && cmake -DARCH=native -DCMAKE_C_FLAGS=-Wa,--noexecstack -DCMAKE_CXX_FLAGS=-Wa,--noexecstack .. && make) && (cd ../Native/librandomx && cp /tmp/RandomX/build/librandomx.a . && make clean && make) && mv ../Native/librandomx/librandomx.so "$OutDir") +((cd /tmp && rm -rf RandomARQ && git clone https://github.com/arqma/RandomARQ && cd RandomARQ && git checkout 3bcb6bafe63d70f8e6f78a0d431e71be2b638083 && mkdir build && cd build && cmake -DARCH=native -DCMAKE_C_FLAGS=-Wa,--noexecstack -DCMAKE_CXX_FLAGS=-Wa,--noexecstack .. && make) && (cd ../Native/librandomarq && cp /tmp/RandomARQ/build/librandomx.a . && make clean && make) && mv ../Native/librandomarq/librandomarq.so "$OutDir") diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index 1c23071b30..d49f7de065 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -36,32 +36,6 @@ "explorerTxLink": "https://explorer.fiveg.cash/tx/{0}", "explorerAccountLink": "https://explorer.fiveg.cash/address/{0}" }, - "anonpay": { - "name": "AnonPay", - "symbol": "ANP", - "family": "bitcoin", - "website": "https://anonpay.net/", - "market": "https://xeggex.com/market/ANP_USDT", - "twitter": "https://twitter.com/AnonPayOfficial", - "discord": "https://discord.com/invite/eKN8aHXkwK", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "keccakc" - }, - "blockHasher": { - "hash": "reverse", - "args": [ { "hash": "sha256d" } ] - }, - "hasFounderFee": true, - "hasMasterNodes": true, - "hasSmartNodes": true, - "shareMultiplier": 256, - "explorerBlockLink": "https://explorer.anonpay.net/block/$height$", - "explorerTxLink": "https://explorer.anonpay.net/tx/{0}", - "explorerAccountLink": "https://explorer.anonpay.net/address/{0}" - }, "auroracoin-sha256": { "name": "Auroracoin Sha256", "canonicalName": "Auroracoin", @@ -203,26 +177,23 @@ "discord": "https://discord.gg/Fhm4758", "coinbaseHasher": { "hash": "sha256d" - }, - "headerHasher": { + }, + "headerHasher": { "hash": "groestl-myriad" - }, - "blockHasher": { + }, + "blockHasher": { "hash": "reverse", "args": [ - { - "hash": "scrypt", - "args": [ - 1024, - 1 - ] - } + { + "hash": "sha256d" + } ] - }, - "blockTemplateRpcExtraParams": [ + }, + "shareMultiplier": 4096, + "blockTemplateRpcExtraParams": [ "groestl" - ], - "explorerBlockLink": "https://chainz.cryptoid.info/aur/block.dws?$height$.htm", + ], + "explorerBlockLink": "https://chainz.cryptoid.info/aur/block.dws?$height$.htm", "explorerTxLink": "https://chainz.cryptoid.info/aur/tx.dws?{0}.htm", "explorerAccountLink": "https://chainz.cryptoid.info/aur/address.dws?{0}.htm" }, @@ -320,37 +291,6 @@ "explorerTxLink": "http://explorer.kriptokyng.com:3001/tx/{0}", "explorerAccountLink": "http://explorer.kriptokyng.com:3001/address/{0}" }, - "bitcore": { - "name": "Bitcore", - "canonicalName": "Bitcore", - "symbol": "BTX", - "family": "bitcoin", - "website": "http://bitcore.cc/", - "market": "https://www.coingecko.com/en/coins/bitcore", - "twitter": "https://twitter.com/bitcore_btx", - "telegram": "", - "discord": "https://discordapp.com/invite/Q8uEjED", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "megabtx" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasMasterNodes": true, - "shareMultiplier": 256, - "coinbaseMinConfimations": 4032, - "explorerBlockLink": "https://chainz.cryptoid.info/btx/block.dws?$height$.htm", - "explorerTxLink": "https://chainz.cryptoid.info/btx/tx.dws?{0}.htm", - "explorerAccountLink": "https://chainz.cryptoid.info/btx/address.dws?{0}.htm" - }, "bitcoin": { "name": "Bitcoin", "canonicalName": "Bitcoin", @@ -492,36 +432,6 @@ "explorerTxLink": "https://explorer.btcnickel.com/tx/{0}", "explorerAccountLink": "https://explorer.btcnickel.com/address/{0}" }, - "bitnet": { - "name": "BitNet", - "canonicalName": "BitNet", - "symbol": "BIT", - "family": "bitcoin", - "website": "https://bitnet-io.org/", - "market": "https://www.coingecko.com/en/coins/bitnet-io", - "github": "https://github.com/bitnet-io/bitnet-core", - "twitter": "https://twitter.com/Bitnet_io", - "telegram": "https://t.me/bitnet00", - "discord": "https://discord.com/invite/6Qq3wvrKRm", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "aurum" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "shareMultiplier": 4096, - "explorerBlockLink": "https://bitchair.io/block/$hash$", - "explorerTxLink": "https://bitchair.io/tx/{0}", - "explorerAccountLink": "https://bitchair.io/address/{0}" - }, "bitflate": { "name": "Bitflate", "canonicalName": "Bitflate", @@ -716,64 +626,6 @@ "explorerTxLink": "https://cann.tokenview.com/en/tx/{0}", "explorerAccountLink": "https://cann.tokenview.com/en/address/{0}" }, - "cpuchain": { - "name": "CPUchain", - "canonicalName": "CPUchain", - "symbol": "CPU", - "family": "bitcoin", - "website": "https://cpuchain.org/", - "twitter": "https://twitter.com/cpuchain/", - "telegram": "https://t.me/cpuchainofficial/", - "discord": "", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "cpupower" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "cpupower" - } - ] - }, - "shareMultiplier": 65536, - "explorerBlockLink": "https://explorer.cpuchain.org/#/block/$hash$", - "explorerTxLink": "https://explorer.cpuchain.org/#/tx/{0}", - "explorerAccountLink": "https://explorer.cpuchain.org/#/address/{0}" - }, - "dadarpay": { - "name": "Dadar Pay", - "symbol": "DDR", - "family": "bitcoin", - "website": "https://dadar.xyz/", - "github": "https://github.com/dadarpay/DDR", - "market": "https://exchange.spectra.cash/#/market/DEX.DDR_DEX.USDT", - "twitter": "https://x.com/CoinDadar", - "telegram": "", - "discord": "https://discord.gg/R32FTyKdXC", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "x11kvs" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "x11kvs" - } - ] - }, - "hasMasterNodes": true, - "hasPayee": true, - "explorerBlockLink": "https://blocks.dadar.xyz/block/$hash$", - "explorerTxLink": "https://blocks.dadar.xyz/tx/{0}", - "explorerAccountLink": "https://blocks.dadar.xyz/address/{0}" - }, "danecoin": { "name": "Danecoin", "canonicalName": "Danecoin", @@ -807,11 +659,11 @@ "canonicalName": "Dash", "symbol": "DASH", "family": "bitcoin", - "website": "https://www.dash.org/", - "market": "https://coinmarketcap.com/currencies/dash", - "twitter": "https://twitter.com/Dashpay", + "website": "", + "market": "", + "twitter": "", "telegram": "", - "discord": "https://discord.com/invite/PXbUxJB", + "discord": "", "coinbaseHasher": { "hash": "sha256d" }, @@ -997,9 +849,9 @@ "canonicalName": "Dogecoin", "symbol": "DOGE", "family": "bitcoin", - "website": "http://dogecoin.com/", - "market": "https://coinmarketcap.com/currencies/dogecoin", - "twitter": "https://twitter.com/dogecoin", + "website": "", + "market": "", + "twitter": "", "telegram": "", "discord": "", "coinbaseHasher": { @@ -1053,7 +905,8 @@ "explorerBlockLink": "https://blockchair.com/ecash/block/$height$", "explorerTxLink": "https://blockchair.com/ecash/transaction/{0}", "explorerAccountLink": "https://blockchair.com/ecash/address/{0}", - "hasMinerFund": true + "hasMinerFund": true, + "hasCoinbaseStakingReward": true }, "emark": { "name": "Deutsche eMark", @@ -1085,33 +938,6 @@ "explorerTxLink": "https://chainz.cryptoid.info/dem/tx.dws?{0}.htm", "explorerAccountLink": "https://chainz.cryptoid.info/dem/address.dws?{0}.htm" }, - "enig": { - "name": "Enig", - "symbol": "ENIG", - "family": "bitcoin", - "website": "https://enigplay.com/", - "github": "https://github.com/enigplay/enig", - "market": "", - "twitter": "https://x.com/weareenig", - "discord": "https://discord.gg/cf3sPZxmXH", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "ghostrider" - }, - "blockHasher": { - "hash": "reverse", - "args": [ { "hash": "sha256d" } ] - }, - "hasFounderFee": true, - "hasMasterNodes": true, - "hasSmartNodes": true, - "shareMultiplier": 65536, - "explorerBlockLink": "https://enigscan.com/block/$height$", - "explorerTxLink": "https://enigscan.com/tx/{0}", - "explorerAccountLink": "https://enigscan.com/address/{0}" - }, "emrals": { "name": "Emrals", "canonicalName": "Emrals", @@ -1380,39 +1206,6 @@ "explorerTxLink": "https://livenet.flocha.in/tx/{0}", "explorerAccountLink": "https://livenet.flocha.in/address/{0}" }, - "fortuneblock": { - "name": "FortuneBlock", - "symbol": "FTB", - "family": "bitcoin", - "website": "https://fortuneblock.xyz/", - "market": "", - "github": "https://github.com/FortuneBlockTeam/fortuneblock", - "explorer": "https://explorer.fortuneblock.xyz/", - "twitter": "https://x.com/Fortune_Block", - "telegram": "", - "discord": "https://discord.com/invite/g4rwqYHkmd", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "mike" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasFounderFee": true, - "hasMasterNodes": true, - "hasSmartNodes": true, - "shareMultiplier": 65536, - "explorerBlockLink": "https://explorer.fortuneblock.xyz/block/$hash$", - "explorerTxLink": "https://explorer.fortuneblock.xyz/tx/{0}", - "explorerAccountLink": "https://explorer.fortuneblock.xyz/address/{0}" - }, "foxdcoin": { "name": "FoxDcoin", "canonicalName": "FoxDcoin", @@ -1479,36 +1272,6 @@ "explorerTxLink": "https://freecash.info/transaction?hash={0}", "explorerAccountLink": "https://freecash.info/address?address={0}" }, - "frencoin": { - "name": "Frencoin", - "symbol": "FREN", - "family": "progpow", - "progpower": "kawpow", - "website": "https://frencoin.org/", - "market": "https://www.coingecko.com/en/coins/frencoin-2", - "twitter": "https://twitter.com/frencoinfren", - "github": "https://github.com/Apushii/Frencoin", - "telegram": "", - "discord": "https://discord.com/invite/CA8ZVtFBEa", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "shareMultiplier": 1, - "explorerBlockLink": "https://explorer.frencoin.org/block/$hash$", - "explorerTxLink": "https://explorer.frencoin.org/tx/{0}", - "explorerAccountLink": "https://explorer.frencoin.org/address/{0}" - }, "geekcash": { "name": "Geek Cash", "symbol": "GEEK", @@ -1551,7 +1314,7 @@ "hash": "sha256s" }, "headerHasher": { - "hash": "groestl-myriad" + "hash": "groestl" }, "blockHasher": { "hash": "reverse", @@ -1576,12 +1339,18 @@ "twitter": "https://twitter.com/hns", "telegram": "https://t.me/handshake_hns", "discord": "https://handshake.org/discord", + "merkleTreeHasher": { + "hash": "blake2b" + }, "coinbaseHasher": { - "hash": "sha3-256" + "hash": "blake2b" }, "headerHasher": { "hash": "blake2b" }, + "shareHasher": { + "hash": "sha3-256" + }, "blockHasher": { "hash": "blake2b" }, @@ -1590,34 +1359,6 @@ "explorerTxLink": "https://e.hnsfans.com/tx/{0}", "explorerAccountLink": "https://e.hnsfans.com/address/{0}" }, - "hellar": { - "name": "Hellar", - "symbol": "HEL", - "family": "bitcoin", - "website": "https://hellar.io/", - "market": "", - "twitter": "https://twitter.com/HellarCore", - "telegram": "", - "discord": "https://discord.gg/U7W5WXxzfT", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "x11gost" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "x11gost" - } - ] - }, - "hasMasterNodes": true, - "explorerBlockLink": "http://chain.hellar.io/block/$hash$", - "explorerTxLink": "http://chain.hellar.io/tx/{0}", - "explorerAccountLink": "http://chain.hellar.io/address/{0}" - }, "help-the-homeless": { "name": "Help The Homeless", "symbol": "HTH", @@ -1692,38 +1433,6 @@ "explorerTxLink": "http://hfrco.in/blockcrawler/tx/{0}", "explorerAccountLink": "http://hfrco.in/blockcrawler/address/{0}" }, - "hootchain": { - "name": "HootChain", - "canonicalName": "HootChain", - "symbol": "HOOT", - "family": "bitcoin", - "website": "https://www.hootchain.org/", - "market": "", - "twitter": "https://x.com/HootChain", - "telegram": "https://t.me/HootChain", - "discord": "https://discord.gg/WEPECmANVy", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "x11" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "x11" - } - ] - }, - "hasMasterNodes": true, - "hasFounderFee": true, - "hasDevFee": true, - "coinbaseMinConfimations": 150, - "explorerBlockLink": "https://explorer.hootchain.org/block/$hash$", - "explorerTxLink": "https://explorer.hootchain.org/tx/{0}", - "explorerAccountLink": "https://explorer.hootchain.org/address/{0}" - }, "indexchain": { "name": "IndexChain", "symbol": "IDX", @@ -1761,31 +1470,34 @@ "explorerTxLink": "http://157.245.248.32:3000/#/tx/{0}", "explorerAccountLink": "http://157.245.248.32:3000/#/address/{0}" }, - "keymaker": { - "name": "Keymaker", - "symbol": "KEYM", + "kylacoin": { + "name": "Kylacoin", + "symbol": "KCN", "family": "bitcoin", - "website": "https://www.keymaker.cc/", - "market": "", - "twitter": "https://twitter.com/keymakercc", - "discord": "https://discord.gg/hEejbJG5uw", + "website": "https://kylacoin.com/", + "market": "https://coinpaprika.com/coin/kcn-kylacoin", + "twitter": "https://twitter.com/kylacoin", + "telegram": "https://t.me/kylacoingroup", + "discord": "https://discord.gg/SHZr5zQVDT", "coinbaseHasher": { - "hash": "sha256d" + "hash": "sha3-256d" }, "headerHasher": { - "hash": "ghostrider" + "hash": "flex" }, "blockHasher": { "hash": "reverse", - "args": [ { "hash": "sha256d" } ] + "args": [ + { + "hash": "sha3-256d" + } + ] }, - "hasFounderFee": true, - "hasMasterNodes": true, - "hasSmartNodes": true, - "shareMultiplier": 65536, - "explorerBlockLink": "https://explorer.keymaker.cc/block/$height$", - "explorerTxLink": "https://explorer.keymaker.cc/tx/{0}", - "explorerAccountLink": "https://explorer.keymaker.cc/address/{0}" + "payoutDecimalPlaces": 12, + "hasCoinbaseDevReward": true, + "explorerBlockLink": "https://kcnxp.com/block/$height$", + "explorerTxLink": "https://kcnxp.com/tx/{0}", + "explorerAccountLink": "https://kcnxp.com/address/{0}" }, "lanacoin": { "name": "Lanacoin", @@ -1848,9 +1560,9 @@ "canonicalName": "Litecoin", "symbol": "LTC", "family": "bitcoin", - "website": "https://litecoin.org/", - "market": "https://coinmarketcap.com/currencies/litecoin", - "twitter": "https://twitter.com/litecoin", + "website": "", + "market": "", + "twitter": "", "telegram": "", "discord": "", "coinbaseHasher": { @@ -1891,14 +1603,14 @@ }, "litecoin-cash": { "name": "Litecoin Cash", - "canonicalName": "Litecoin-Cash (no ASICBoost)", + "canonicalName": "Litecoin-Cash", "symbol": "LCC", "family": "bitcoin", - "website": "https://litecoinca.sh/", - "market": "https://coinpaprika.com/coin/lch-litecoincash", - "twitter": "https://twitter.com/litecoincash", + "website": "", + "market": "", + "twitter": "", "telegram": "", - "discord": "https://discordapp.com/invite/F2nZXnW", + "discord": "", "coinbaseHasher": { "hash": "sha256d" }, @@ -1917,41 +1629,13 @@ "explorerTxLink": "https://chainz.cryptoid.info/lcc/tx.dws?{0}.htm", "explorerAccountLink": "https://chainz.cryptoid.info/lcc/address.dws?{0}.htm" }, - "litecoin-cash-minotaurx": { - "name": "Litecoin Cash Minotaurx", - "canonicalName": "Litecoin-Cash", - "symbol": "LCC", + "luckybit": { + "name": "Lucky Bit", + "symbol": "LUCKY", "family": "bitcoin", - "website": "https://litecoinca.sh/", - "market": "https://coinpaprika.com/coin/lch-litecoincash", - "twitter": "https://twitter.com/litecoincash", - "telegram": "", - "discord": "https://discordapp.com/invite/F2nZXnW", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "minotaurx" - }, - "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" - }, - "luckybit": { - "name": "Lucky Bit", - "symbol": "LUCKY", - "family": "bitcoin", - "website": "", - "market": "", - "twitter": "", + "website": "", + "market": "", + "twitter": "", "telegram": "", "discord": "", "coinbaseHasher": { @@ -1980,110 +1664,16 @@ "explorerTxLink": "https://openchains.info/coin/luckybit/tx/{0}", "explorerAccountLink": "https://openchains.info/coin/luckybit/address/{0}" }, - "mateable": { - "name": "Mateable Coin", - "canonicalName": "Mateable", - "symbol": "MTBC", - "family": "bitcoin", - "website": "https://coin.mateable.com/", - "twitter": "https://twitter.com/mateable", - "telegram": "https://t.me/mateablecoin", - "discord": "", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "scrypt", - "args": [ - 1024, - 1 - ] - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "blockTemplateRpcExtraParams": [ - "scrypt" - ], - "shareMultiplier": 65536, - "explorerBlockLink": "https://explorer.mateable.com/block/$hash$", - "explorerTxLink": "https://explorer.mateable.com/tx/{0}", - "explorerAccountLink": "https://explorer.mateable.com/address/{0}" - }, - "mateable-yescrypt": { - "name": "Mateable Coin", - "canonicalName": "Mateable", - "symbol": "MTBC", - "family": "bitcoin", - "website": "https://coin.mateable.com/", - "twitter": "https://twitter.com/mateable", - "telegram": "https://t.me/mateablecoin", - "discord": "", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "yescryptr8" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "shareMultiplier": 65536, - "explorerBlockLink": "https://explorer.mateable.com/block/$hash$", - "explorerTxLink": "https://explorer.mateable.com/tx/{0}", - "explorerAccountLink": "https://explorer.mateable.com/address/{0}" - }, - "mateable-ghostrider": { - "name": "Mateable Coin", - "canonicalName": "Mateable", - "symbol": "MTBC", - "family": "bitcoin", - "website": "https://coin.mateable.com/", - "market": "https://coinpaprika.com/coin/mtbc-mateablecoin", - "twitter": "https://twitter.com/mateable", - "telegram": "https://t.me/mateablecoin", - "discord": "", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "ghostrider" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasMasterNodes": true, - "hasSmartNodes": true, - "shareMultiplier": 65536, - "explorerBlockLink": "https://explorer.mateable.com/block/$hash$", - "explorerTxLink": "https://explorer.mateable.com/tx/{0}", - "explorerAccountLink": "https://explorer.mateable.com/address/{0}" - }, "maza": { "name": "Maza", - "canonicalName": "Mazacoin", + "canonicalName": "Maza", "symbol": "MAZA", "family": "bitcoin", - "website": "http://www.mazacoin.org/", - "market": "https://www.coingecko.com/en/coins/maza", - "twitter": "https://twitter.com/MazaCoin", - "telegram": "https://t.me/mazatribe", - "discord": "https://discord.com/invite/qzd9PnzN3v", + "website": "", + "market": "", + "twitter": "", + "telegram": "", + "discord": "", "coinbaseHasher": { "hash": "sha256d" }, @@ -2102,62 +1692,6 @@ "explorerTxLink": "https://mazacha.in/tx/{0}", "explorerAccountLink": "https://mazacha.in/address/{0}" }, - "maza-minotaurx": { - "name": "Maza", - "canonicalName": "Mazacoin", - "symbol": "MAZA", - "family": "bitcoin", - "website": "http://www.mazacoin.org/", - "market": "https://www.coingecko.com/en/coins/maza", - "twitter": "https://twitter.com/MazaCoin", - "telegram": "https://t.me/mazatribe", - "discord": "https://discord.com/invite/qzd9PnzN3v", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "minotaurx" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "explorerBlockLink": "https://mazacha.in/block/$hash$", - "explorerTxLink": "https://mazacha.in/tx/{0}", - "explorerAccountLink": "https://mazacha.in/address/{0}" - }, - "microbitcoin": { - "name": "MicroBitcoin", - "canonicalName": "MicroBitcoin", - "symbol": "MBC", - "family": "bitcoin", - "website": "https://microbitcoin.org/", - "twitter": "https://twitter.com/MicroBitcoinOrg", - "telegram": "", - "discord": "https://discordapp.com/invite/JuRrekx", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "power2b" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "blake2b" - } - ] - }, - "shareMultiplier": 65536, - "explorerBlockLink": "https://microbitcoinorg.github.io/explorer/#/block/$hash$", - "explorerTxLink": "https://microbitcoinorg.github.io/explorer/#/transaction/{0}", - "explorerAccountLink": "https://microbitcoinorg.github.io/explorer/#/address/{0}" - }, "mincoin": { "name": "Mincoin", "canonicalName": "Mincoin", @@ -2457,47 +1991,16 @@ "explorerTxLink": "https://chainz.cryptoid.info/pak/tx.dws?{0}.htm", "explorerAccountLink": "https://chainz.cryptoid.info/pak/address.dws?{0}.htm" }, - "pepepow": { - "name": "PepePow", - "canonicalName": "PepePow", - "symbol": "PEPEW", - "family": "bitcoin", - "website": "https://pepepow.org/", - "market": "https://www.coingecko.com/en/coins/pepepow", - "twitter": "https://twitter.com/PEPEWCommunity", - "telegram": "https://t.me/pepewcommunity", - "discord": "https://discord.com/invite/sJgDVRkBcq", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "xelisv2-pepew" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "xelisv2-pepew" - } - ] - }, - "hasMasterNodes": true, - "hasFoundation": true, - "shareMultiplier": 65536, - "explorerBlockLink": "https://explorer.pepepow.org/block/$hash$", - "explorerTxLink": "https://explorer.pepepow.org/tx/{0}", - "explorerAccountLink": "https://explorer.pepepow.org/address/{0}" - }, "peercoin": { "name": "Peercoin", "canonicalName": "Peercoin", "symbol": "PPC", "family": "bitcoin", - "website": "http://www.peercoin.net/", - "market": "https://coinmarketcap.com/currencies/peercoin", - "twitter": "https://twitter.com/peercoinppc", + "website": "", + "market": "", + "twitter": "", "telegram": "", - "discord": "https://discord.gg/m294ReV", + "discord": "", "coinbaseHasher": { "hash": "sha256d" }, @@ -2749,77 +2252,14 @@ "hasFounderFee": true, "hasMasterNodes": true, "hasSmartNodes": true, + "foundersRewardAddress": [ + "RTtyQU6DoSuNWetT4WUem5qXP5jNYGpwat" + ], "shareMultiplier": 65536, "explorerBlockLink": "https://explorer.raptoreum.com/block-height/$height$", "explorerTxLink": "https://explorer.raptoreum.com/tx/{0}", "explorerAccountLink": "https://explorer.raptoreum.com/address/{0}" }, - "rheix": { - "name": "Rheix", - "canonicalName": "Rheix", - "symbol": "RHX", - "family": "bitcoin", - "website": "https://rheix.com/", - "market": "", - "twitter": "", - "telegram": "", - "discord": "https://discord.gg/9wgVDHMMyR", - "github": "https://github.com/rheixverse/rheix", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "ghostrider" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasFounderFee": true, - "hasMasterNodes": true, - "hasSmartNodes": true, - "shareMultiplier": 65536, - "explorerBlockLink": "https://explorer.rheix.com/block/$hash$", - "explorerTxLink": "https://explorer.rheix.com/tx/{0}", - "explorerAccountLink": "https://explorer.rheix.com/address/{0}" - }, - "fewbit": { - "name": "FewBit", - "canonicalName": "FewBit", - "symbol": "FBIT", - "family": "bitcoin", - "website": "https://fewbit.net/", - "market": "", - "twitter": "", - "telegram": "https://t.me/+eMGB15LzvLk0MGZk", - "discord": "https://discord.gg/bwdsukjDyj", - "github": "https://github.com/FewBit-Coin/Core-Wallet", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "ghostrider" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasFounderFee": true, - "hasMasterNodes": true, - "hasSmartNodes": true, - "shareMultiplier": 65536, - "explorerBlockLink": "https://fewbit.online/block/$hash$", - "explorerTxLink": "https://fewbit.online/tx/{0}", - "explorerAccountLink": "https://fewbit.online/address/{0}" - }, "gspcoin": { "name": "Gsp Coin", "canonicalName": "GspCoin", @@ -2845,28 +2285,29 @@ }, "hasFounderFee": true, "hasMasterNodes": true, - "hasSmartNodes": true, + "foundersRewardAddress": [ + "GZBNAiLokyYvSwNLftReXuYbvdmzNoorGj" + ], "shareMultiplier": 65536, "explorerBlockLink": "https://explorer.globalsocialpost.com/block/$height$", "explorerTxLink": "https://explorer.globalsocialpost.com/tx/{0}", "explorerAccountLink": "https://explorer.globalsocialpost.com/address/{0}" }, - "anokas": { - "name": "Anokas", - "symbol": "ANOK", - "family": "progpow", - "progpower": "kawpow", - "website": "https://anokas.tech/", - "github": "https://github.com/anokastech/Anokas-mainnet", - "market": "https://www.coingecko.com/en/coins/anokas-network", - "twitter": "https://twitter.com/anokas_network", - "telegram": "https://t.me/anokas_tech", - "discord": "https://discord.com/invite/8B8pAtA2Y5", + "fortuneblock": { + "name": "Fortuneblock", + "canonicalName": "Fortuneblock", + "symbol": "FTB", + "family": "bitcoin", + "website": "https://fortuneblock.xyz/", + "market": "", + "twitter": "https://x.com/Fortune_Block", + "telegram": "", + "discord": "https://discord.gg/g4rwqYHkmd", "coinbaseHasher": { "hash": "sha256d" }, "headerHasher": { - "hash": "sha256d" + "hash": "mike" }, "blockHasher": { "hash": "reverse", @@ -2876,13 +2317,13 @@ } ] }, - "shareMultiplier": 1, - "hasFounderFee": true, + "hasFortuneReward": true, "hasMasterNodes": true, "hasSmartNodes": true, - "explorerBlockLink": "https://explorer.anokas.tech/block/$hash$", - "explorerTxLink": "https://explorer.anokas.tech/tx/{0}", - "explorerAccountLink": "https://explorer.anokas.tech/address/{0}" + "shareMultiplier": 65536, + "explorerBlockLink": "https://explorer.fortuneblock.xyz/block/$hash$", + "explorerTxLink": "https://explorer.fortuneblock.xyz/tx/{0}", + "explorerAccountLink": "https://explorer.fortuneblock.xyz/address/{0}" }, "radiant": { "name": "Radiant", @@ -2931,39 +2372,6 @@ "explorerTxLink": "https://ravencoin.network/rvn/transaction/{0}", "explorerAccountLink": "https://ravencoin.network/rvn/address/{0}" }, - "ravencash": { - "name": "Ravencash", - "symbol": "RVH", - "family": "progpow", - "progpower": "kawpow", - "website": "https://ravencash.net/", - "github": "https://github.com/ravencash-net/ravencash", - "market": "", - "twitter": "https://x.com/ravencash_net", - "telegram": "", - "discord": "https://discord.com/invite/NVwcw3P2FF", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "shareMultiplier": 1, - "hasFounderFee": true, - "hasMasterNodes": true, - "hasSmartNodes": true, - "explorerBlockLink": "https://explorer.ravencash.net/block/$hash$", - "explorerTxLink": "https://explorer.ravencash.net/tx/{0}", - "explorerAccountLink": "https://explorer.ravencash.net/address/{0}" - }, "firo": { "name": "Firo", "symbol": "FIRO", @@ -2995,23 +2403,20 @@ "explorerTxLink": "https://explorer.firo.org/tx/{0}", "explorerAccountLink": "https://explorer.firo.org/address/{0}" }, - "fuertecoin": { - "name": "Fuertecoin", - "canonicalName": "Fuertecoin", - "symbol": "FUEC", - "family": "bitcoin", - "website": "https://fuertecoin.network/", - "market": "", - "github": "https://github.com/GitFuec/fuertecoin", - "explorer": "http://explorer.fuertecoin.network:3001/", - "twitter": "", - "telegram": "", - "discord": "https://discord.gg/YNfBaK95J4", + "neurai": { + "name": "Neurai", + "symbol": "XNA", + "family": "progpow", + "website": "https://neurai.org/", + "market": "https://coinmarketcap.com/currencies/neurai/", + "twitter": "https://twitter.com/neuraiproject", + "telegram": "https://t.me/neuraiproject", + "discord": "https://discord.com/invite/dxJSrSeXjF", "coinbaseHasher": { "hash": "sha256d" }, "headerHasher": { - "hash": "ghostrider" + "hash": "sha256d" }, "blockHasher": { "hash": "reverse", @@ -3021,109 +2426,11 @@ } ] }, - "hasFounderFee": true, - "hasMasterNodes": true, - "hasSmartNodes": true, - "shareMultiplier": 65536, - "explorerBlockLink": "http://explorer.fuertecoin.network:3001/block/$hash$", - "explorerTxLink": "http://explorer.fuertecoin.network:3001/tx/{0}", - "explorerAccountLink": "http://explorer.fuertecoin.network:3001/address/{0}" - }, - "kiirocoin": { - "name": "KiiroCoin", - "symbol": "KIIRO", - "family": "progpow", - "website": "https://kiirocoin.org/", - "market": "https://coinpaprika.com/coin/kiiro-kiirocoin", - "twitter": "https://twitter.com/kiirocoin", - "telegram": "https://t.me/kiirocoin", - "discord": "https://discord.com/invite/yFbbrtPscq", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasCommunity": true, - "hasDeveloper": true, - "hasDataMining": true, - "hasMasterNodes": true, - "shareMultiplier": 1, - "progpower": "firopow", - "explorerBlockLink": "https://explorer.kiirocoin.org/block/$hash$", - "explorerTxLink": "https://explorer.kiirocoin.org/tx/{0}", - "explorerAccountLink": "https://explorer.kiirocoin.org/address/{0}" - }, - "realichain": { - "name": "Realichain", - "symbol": "REALI", - "family": "progpow", - "progpower": "firopow", - "website": "https://realichain.org/", - "github": "https://github.com/Realichain/realichain", - "market": "", - "twitter": "", - "telegram": "", - "discord": "https://discord.gg/JnSJRtnwQq", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasCommunity": true, - "hasDeveloper": true, - "hasDataMining": true, - "hasMasterNodes": true, - "shareMultiplier": 1, - "explorerBlockLink": "https://blockscan.realichain.org/block/$hash$", - "explorerTxLink": "https://blockscan.realichain.org/tx/{0}", - "explorerAccountLink": "https://blockscan.realichain.org/address/{0}" - }, - "neurai": { - "name": "Neurai", - "symbol": "XNA", - "family": "progpow", - "website": "https://neurai.org/", - "market": "https://coinmarketcap.com/currencies/neurai/", - "twitter": "https://twitter.com/neuraiproject", - "telegram": "https://t.me/neuraiproject", - "discord": "https://discord.com/invite/dxJSrSeXjF", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "shareMultiplier": 1, - "progpower": "kawpow", - "explorerBlockLink": "https://explorer.neurai.org/block/$hash$", - "explorerTxLink": "https://explorer.neurai.org/tx/{0}", - "explorerAccountLink": "https://explorer.neurai.org/address/{0}" + "shareMultiplier": 1, + "progpower": "kawpow", + "explorerBlockLink": "https://explorer.neurai.org/block/$hash$", + "explorerTxLink": "https://explorer.neurai.org/tx/{0}", + "explorerAccountLink": "https://explorer.neurai.org/address/{0}" }, "clore": { "name": "Clore", @@ -3155,36 +2462,6 @@ "explorerTxLink": "https://exploreblockchain.clore.ai/tx/{0}", "explorerAccountLink": "https://exploreblockchain.clore.ai/address/{0}" }, - "cmusicai": { - "name": "CmusicAI", - "symbol": "CMS", - "family": "progpow", - "website": "https://cmusic.ai/", - "market": "https://www.coingecko.com/en/coins/cmusicai", - "twitter": "https://twitter.com/cmusicai", - "telegram": "", - "discord": "https://discord.com/invite/EanhmGKxcg", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasCommunityAddress": true, - "shareMultiplier": 1, - "progpower": "kawpow", - "explorerBlockLink": "https://explorer.cmusic.ai/block/$hash$", - "explorerTxLink": "https://explorer.cmusic.ai/tx/{0}", - "explorerAccountLink": "https://explorer.cmusic.ai/address/{0}" - }, "meowcoin": { "name": "Meowcoin", "symbol": "MEWC", @@ -3215,202 +2492,6 @@ "explorerTxLink": "https://mewc.cryptoscope.io/tx/?txid={0}", "explorerAccountLink": "https://mewc.cryptoscope.io/address/?address={0}" }, - "dogegpu": { - "name": "DogeGPU", - "symbol": "DOGPU", - "family": "progpow", - "progpower": "kawpow", - "website": "https://dogegpu.org/", - "github": "https://github.com/Masterscooper/DogeGPU", - "market": "", - "twitter": "https://x.com/dogegpu", - "telegram": "", - "discord": "https://discord.gg/Vg8WDug6Yb", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "shareMultiplier": 1, - "explorerBlockLink": "https://dogpu.cryptoscope.io/block/?blockhash=$hash$", - "explorerTxLink": "https://dogpu.cryptoscope.io/tx/?txid={0}", - "explorerAccountLink": "https://dogpu.cryptoscope.io/address/?address={0}" - }, - "phicoin": { - "name": "Phicoin", - "symbol": "PHI", - "family": "progpow", - "progpower": "phihash", - "website": "https://phicoin.net/", - "github": "https://github.com/PhicoinProject/phicoin", - "market": "", - "twitter": "https://x.com/PhicoinNet", - "telegram": "https://t.me/phicoin_official", - "discord": "https://discord.gg/phicoin", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasCommunityAddress": true, - "shareMultiplier": 1, - "explorerBlockLink": "https://explorer.phicoin.net/block/$hash$", - "explorerTxLink": "https://explorer.phicoin.net/tx/{0}", - "explorerAccountLink": "https://explorer.phicoin.net/address/{0}" - }, - "telestai": { - "name": "Telestai", - "symbol": "TLS", - "family": "progpow", - "progpower": "meraki", - "website": "https://www.telestai.io/", - "market": "", - "twitter": "https://x.com/Telestai_io", - "telegram": "", - "discord": "https://discord.gg/VmFXfHnZE5", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasFounderFee": true, - "shareMultiplier": 1, - "explorerBlockLink": "https://telestai.cryptoscope.io/block/?blockhash=$hash$", - "explorerTxLink": "https://telestai.cryptoscope.io/tx/?txid={0}", - "explorerAccountLink": "https://telestai.cryptoscope.io/address/?address={0}" - }, - "joss": { - "name": "Joss Network", - "symbol": "JOSS", - "family": "bitcoin", - "website": "https://joss.network/", - "market": "", - "github": "https://github.com/jossnetwork/joss", - "twitter": "https://x.com/runonjoss", - "telegram": "", - "discord": "https://discord.gg/XPRMRfyXFA", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "allium" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasFounderFee": true, - "hasMasterNodes": true, - "hasSmartNodes": true, - "shareMultiplier": 256, - "explorerBlockLink": "https://explorer.joss.network/block/$hash$", - "explorerTxLink": "https://explorer.joss.network/tx/{0}", - "explorerAccountLink": "https://explorer.joss.network/address/{0}" - }, - "ogva": { - "name": "OGVA Network", - "symbol": "OGVA", - "family": "bitcoin", - "website": "https://ogva.net/", - "github": "https://github.com/ogvanetwork/ogva-core", - "market": "", - "twitter": "https://x.com/Ogva_network", - "telegram": "https://t.me/ogvanetwork", - "discord": "https://discord.gg/Z3FKGuzKXv", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "neoscrypt", - "args": [ - 0 - ] - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "neoscrypt", - "args": [ - 0 - ] - } - ] - }, - "hasFounderFee": true, - "hasMasterNodes": true, - "hasCommunity": true, - "hasDeveloper": true, - "shareMultiplier": 65536, - "explorerBlockLink": "https://explorer.ogva.net/block/$hash$", - "explorerTxLink": "https://explorer.ogva.net/tx/{0}", - "explorerAccountLink": "https://explorer.ogva.net/address/{0}" - }, - "ultronai": { - "name": "UltronAI", - "canonicalName": "UltronAI", - "symbol": "UTO", - "family": "bitcoin", - "website": "https://ultronai.org/", - "market": "", - "github": "https://github.com/aidevpin", - "explorer": "http://explorer.fuertecoin.network:3001/", - "twitter": "https://x.com/ultronaiorg", - "telegram": "", - "discord": "https://discord.gg/hwmyvFKuNk", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "ghostrider" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasFounderFee": true, - "hasMasterNodes": true, - "hasSmartNodes": true, - "shareMultiplier": 65536, - "explorerBlockLink": "http://explorer.ultronai.org/block/$hash$", - "explorerTxLink": "http://explorer.ultronai.org/tx/{0}", - "explorerAccountLink": "http://explorer.ultronai.org/address/{0}" - }, "aipg": { "name": "AI Power Grid", "symbol": "AIPG", @@ -3488,52 +2569,6 @@ "explorerTxLink": "https://explorer.novochain.ovh/tx/{0}", "explorerAccountLink": "https://explorer.novochain.ovh/address/{0}" }, - "plexhive-sha256d": { - "name": "PlexHive", - "symbol": "PLHV", - "family": "bitcoin", - "website": "http://www.plexhive.com/", - "github": "https://github.com/PlexHive/PlexHive", - "market": "", - "twitter": "https://www.twitter.com/PlexHive_PLHV", - "discord": "https://discord.gg/GrvXQGtn", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [ { "hash": "sha256d" } ] - }, - "explorerBlockLink": "http://explorer.plexhive.com/block/$hash$", - "explorerTxLink": "http://explorer.plexhive.com/tx/{0}", - "explorerAccountLink": "http://explorer.plexhive.com/address/{0}" - }, - "plexhive-minotaurx": { - "name": "PlexHive", - "symbol": "PLHV", - "family": "bitcoin", - "website": "http://www.plexhive.com/", - "github": "https://github.com/PlexHive/PlexHive", - "market": "", - "twitter": "https://www.twitter.com/PlexHive_PLHV", - "discord": "https://discord.gg/GrvXQGtn", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "minotaurx" - }, - "blockHasher": { - "hash": "reverse", - "args": [ { "hash": "sha256d" } ] - }, - "explorerBlockLink": "http://explorer.plexhive.com/block/$hash$", - "explorerTxLink": "http://explorer.plexhive.com/tx/{0}", - "explorerAccountLink": "http://explorer.plexhive.com/address/{0}" - }, "pulsar": { "name": "Pulsar", "symbol": "PLSR", @@ -3553,38 +2588,35 @@ "args": [ { "hash": "minotaurx" } ] }, "isPseudoPoS": true, - "explorerBlockLink": "https://explorer.pulsarcoin.org/block/$height$", - "explorerTxLink": "https://explorer.pulsarcoin.org/tx/{0}", - "explorerAccountLink": "https://explorer.pulsarcoin.org/address/{0}" - }, - "magpiecoin": { - "name": "MagPieCoin", - "canonicalName": "MagPieCoin", - "symbol": "MGPC", + "explorerBlockLink": "https://explorer.pulsarcoin.org/block/?blockheight=$height$", + "explorerTxLink": "https://explorer.pulsarcoin.org/tx/?txid={0}", + "explorerAccountLink": "https://explorer.pulsarcoin.org/address/?address={0}" + }, + "vishai": { + "name": "Vishai", + "canonicalName": "VishAI", + "symbol": "VISH", "family": "bitcoin", - "website": "http://magpiecoin.animalcoins.top/", - "twitter": "https://twitter.com/mareels1", - "telegram": "", - "discord": "https://discord.gg/jBx52PNxdp", + "website": "https://vishcoin.com/", + "market": "", + "twitter": "https://twitter.com/vishcoinai", + "telegram": "https://t.me/vishaiofficial", + "discord": "https://discord.gg/cxCfHuNpWn", "coinbaseHasher": { "hash": "sha256d" }, "headerHasher": { - "hash": "yespowermgpc" + "hash": "yespower" }, "blockHasher": { "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] + "args": [ { "hash": "yespower" } ] }, + "hasMasterNodes": true, "shareMultiplier": 65536, - "coinbaseMinConfimations": 340, - "explorerBlockLink": "http://mgpcexplorer.animalcoins.top:3030/block/$height$", - "explorerTxLink": "http://mgpcexplorer.animalcoins.top:3030/tx/{0}", - "explorerAccountLink": "http://mgpcexplorer.animalcoins.top:3030/address/{0}" + "explorerBlockLink": "https://explorer.vishcoin.com/block/$hash$", + "explorerTxLink": "https://explorer.vishcoin.com/tx/{0}", + "explorerAccountLink": "https://explorer.vishcoin.com/address/{0}" }, "bitoreum": { "name": "Bitoreum", @@ -3612,6 +2644,9 @@ "hasFounderFee": true, "hasMasterNodes": true, "hasSmartNodes": true, + "foundersRewardAddress": [ + "BanxgMPcMpXnuWQ2ogfQqEkwwVtjhAhXBR" + ], "shareMultiplier": 65536, "explorerBlockLink": "https://explorer.bitoreum.org/block/$hash$", "explorerTxLink": "https://explorer.bitoreum.org/tx/{0}", @@ -3699,32 +2734,6 @@ "explorerTxLink": "https://explorer.shroudx.eu/tx/{0}", "explorerAccountLink": "https://explorer.shroudx.eu/address/{0}" }, - "smartiecoin": { - "name": "SmartieCoin", - "canonicalName": "SmartieCoin", - "symbol": "SMT", - "family": "bitcoin", - "website": "https://smartiescoin.com/", - "market": "https://coinpaprika.com/coin/smt-smartiecoin", - "twitter": "https://twitter.com/SmartieCoin", - "telegram": "", - "discord": "https://discord.com/invite/XXKUqCzK8Q", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "yespower" - }, - "blockHasher": { - "hash": "reverse", - "args": [ { "hash": "yespower" } ] - }, - "hasMasterNodes": true, - "shareMultiplier": 65536, - "explorerBlockLink": "https://chainz.cryptoid.info/smartie/block.dws?$height$.htm", - "explorerTxLink": "https://chainz.cryptoid.info/smartie/tx.dws?{0}.htm", - "explorerAccountLink": "https://chainz.cryptoid.info/smartie/address.dws?{0}.htm" - }, "smileycoin-sha256": { "name": "Smileycoin Sha256", "canonicalName": "Smileycoin", @@ -3922,41 +2931,11 @@ "explorerTxLink": "https://chainz.cryptoid.info/spk/tx.dws?{0}.htm", "explorerAccountLink": "https://chainz.cryptoid.info/spk/address.dws?{0}.htm" }, - "skydoge": { - "name": "Skydoge", - "canonicalName": "Skydoge", - "symbol": "SKYDOGE", - "family": "bitcoin", - "website": "https://skydoge.net/", - "market": "", - "twitter": "https://twitter.com/skydogenet", - "telegram": "https://t.me/skydoge_net", - "discord": "https://discord.com/invite/GKHGDGbt8S", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "skydoge" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "skydoge" - } - ] - }, - "coinbaseTxVersion": 9, - "explorerBlockLink": "https://explorer.skydoge.net/block/$hash$", - "explorerTxLink": "https://explorer.skydoge.net/tx/{0}", - "explorerAccountLink": "https://explorer.skydoge.net/address/{0}" - }, "stakecube": { "name": "StakeCube", "canonicalName": "Stakecube", "symbol": "SCC", - "family": "progpow", - "progpower": "sccpow", + "family": "bitcoin", "website": "https://stakecube.net/", "market": "https://coinmarketcap.com/currencies/stakecubecoin", "twitter": "https://twitter.com/stakecube", @@ -3966,18 +2945,17 @@ "hash": "sha256d" }, "headerHasher": { - "hash": "sha256d" + "hash": "x11" }, "blockHasher": { "hash": "reverse", "args": [ { - "hash": "sha256d" + "hash": "x11" } ] }, "hasMasterNodes": true, - "shareMultiplier": 1, "explorerBlockLink": "https://scc.ccore.online/block/$height$", "explorerTxLink": "https://scc.ccore.online/tx/{0}", "explorerAccountLink": "https://scc.ccore.online/address/{0}" @@ -4306,14 +3284,14 @@ }, "verge-lyra": { "name": "Verge Lyra", - "canonicalName": "Verge LyraREv2", + "canonicalName": "Verge", "symbol": "XVG", "family": "bitcoin", - "website": "http://vergecurrency.com/", - "market": "https://coinmarketcap.com/currencies/verge", - "twitter": "https://twitter.com/vergecurrency", + "website": "", + "market": "", + "twitter": "", "telegram": "", - "discord": "https://discord.gg/vergecurrency", + "discord": "", "coinbaseHasher": { "hash": "sha256d" }, @@ -4343,14 +3321,14 @@ }, "verge-scrypt": { "name": "Verge-Scrypt", - "canonicalName": "Verge Scrypt", + "canonicalName": "Verge", "symbol": "XVG", "family": "bitcoin", - "website": "http://vergecurrency.com/", - "market": "https://coinmarketcap.com/currencies/verge", - "twitter": "https://twitter.com/vergecurrency", + "website": "", + "market": "", + "twitter": "", "telegram": "", - "discord": "https://discord.gg/vergecurrency", + "discord": "", "coinbaseHasher": { "hash": "sha256d" }, @@ -4365,29 +3343,33 @@ "hash": "reverse", "args": [ { - "hash": "sha256d" + "hash": "scrypt", + "args": [ + 1024, + 1 + ] } ] }, + "isPseudoPoS": true, "blockTemplateRpcExtraParams": [ "scrypt" ], "shareMultiplier": 65536, - "forcePoolAddressDestinationWithPubKey": true, "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", - "canonicalName": "Verge X17", + "canonicalName": "Verge", "symbol": "XVG", "family": "bitcoin", - "website": "http://vergecurrency.com/", - "market": "https://coinmarketcap.com/currencies/verge", - "twitter": "https://twitter.com/vergecurrency", + "website": "", + "market": "", + "twitter": "", "telegram": "", - "discord": "https://discord.gg/vergecurrency", + "discord": "", "coinbaseHasher": { "hash": "sha256d" }, @@ -4416,14 +3398,14 @@ }, "verge-blake": { "name": "Verge Blake", - "canonicalName": "Verge Blake", + "canonicalName": "Verge", "symbol": "XVG", "family": "bitcoin", - "website": "http://vergecurrency.com/", - "market": "https://coinmarketcap.com/currencies/verge", - "twitter": "https://twitter.com/vergecurrency", + "website": "", + "market": "", + "twitter": "", "telegram": "", - "discord": "https://discord.gg/vergecurrency", + "discord": "", "coinbaseHasher": { "hash": "sha256d" }, @@ -4452,35 +3434,35 @@ }, "verge-groestl": { "name": "Verge Groestl", - "canonicalName": "Verge Myriad Groestl ", + "canonicalName": "Verge", "symbol": "XVG", "family": "bitcoin", - "website": "http://vergecurrency.com/", - "market": "https://coinmarketcap.com/currencies/verge", - "twitter": "https://twitter.com/vergecurrency", + "website": "", + "market": "", + "twitter": "", "telegram": "", - "discord": "https://discord.gg/vergecurrency", + "discord": "", "coinbaseHasher": { - "hash": "sha256d" + "hash": "sha256d" }, "headerHasher": { - "hash": "groestl-myriad" + "hash": "groestl-myriad" }, "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "scrypt", - "args": [ - 1024, - 1 - ] - } - ] + "hash": "reverse", + "args": [ + { + "hash": "scrypt", + "args": [ + 1024, + 1 + ] + } + ] }, "isPseudoPoS": true, "blockTemplateRpcExtraParams": [ - "myr-groestl" + "groestl" ], "explorerBlockLink": "https://verge-blockchain.info/block/$hash$", "explorerTxLink": "https://verge-blockchain.info/tx/{0}", @@ -4559,32 +3541,6 @@ "explorerTxLink": "https://chainz.cryptoid.info/via/tx.dws?{0}.htm", "explorerAccountLink": "https://chainz.cryptoid.info/via/address.dws?{0}.htm" }, - "vishai": { - "name": "Vishai", - "canonicalName": "VishAI", - "symbol": "VISH", - "family": "bitcoin", - "website": "https://vishcoin.com/", - "market": "", - "twitter": "https://twitter.com/vishcoinai", - "telegram": "https://t.me/vishaiofficial", - "discord": "https://discord.gg/cxCfHuNpWn", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "yespower" - }, - "blockHasher": { - "hash": "reverse", - "args": [ { "hash": "yespower" } ] - }, - "hasMasterNodes": true, - "shareMultiplier": 65536, - "explorerBlockLink": "https://explorer.vishcoin.com/block/$hash$", - "explorerTxLink": "https://explorer.vishcoin.com/tx/{0}", - "explorerAccountLink": "https://explorer.vishcoin.com/address/{0}" - }, "voltpotcoin": { "name": "Volt Pot Coin", "canonicalName": "Auroracoin", @@ -4658,34 +3614,6 @@ "explorerTxLink": "https://explorer.widecoin.org/tx/{0}", "explorerAccountLink": "https://explorer.widecoin.org/address/{0}" }, - "woodcoin": { - "name": "Woodcoin", - "canonicalName": "Woodcoin", - "symbol": "LOG", - "family": "bitcoin", - "website": "https://woodcoin.org/", - "market": "https://coinmarketcap.com/currencies/woodcoin/", - "twitter": "https://twitter.com/woodcoin_jp", - "telegram": "", - "discord": "", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "skein2" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "explorerBlockLink": "https://explorer.woodcoin.org/block/$hash$", - "explorerTxLink": "https://explorer.woodcoin.org/tx/{0}", - "explorerAccountLink": "https://explorer.woodcoin.org/address/{0}" - }, "worldcoin": { "name": "Worldcoin", "canonicalName": "Worldcoin", @@ -4808,66 +3736,6 @@ "explorerTxLink": "https://explorer.yerbas.org/tx/{0}", "explorerAccountLink": "https://explorer.yerbas.org/address/{0}" }, - "yenten": { - "name": "Yenten", - "canonicalName": "Yenten", - "symbol": "YTN", - "family": "bitcoin", - "website": "http://yentencoin.info/", - "twitter": "https://twitter.com/yentencoin", - "telegram": "https://t.me/yenten", - "discord": "https://discord.gg/RTbPxu3", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "yespowerr16" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "shareMultiplier": 65536, - "explorerBlockLink": "http://ytn.ccore.online/block/$height$", - "explorerTxLink": "http://ytn.ccore.online/transaction/{0}", - "explorerAccountLink": "http://ytn.ccore.online/address/{0}" - }, - "zero-dynamics-cash": { - "name": "Zero Dynamics Cash", - "symbol": "0DYNC", - "family": "bitcoin", - "website": "http://zero-dynamics.org", - "market": "https://app.exbitron.com/exchange/?market=0DYNC-USDT", - "github": "https://github.com/Zero-Dynamics/cash-core", - "explorer": "http://154.92.17.70:3008/", - "twitter": "https://x.com/Zero_Dyn_", - "telegram": "https://t.me/Zero_Dynamics", - "discord": "https://discord.gg/4W8WfW9qje", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "argon2d1000" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "argon2d1000" - } - ] - }, - "hasMasterNodes": true, - "shareMultiplier": 65536, - "coinbaseMinConfimations": 40, - "explorerBlockLink": "http://154.92.17.70:3008/block/$hash$", - "explorerTxLink": "http://154.92.17.70:3008/tx/{0}", - "explorerAccountLink": "http://154.92.17.70:3008/address/{0}" - }, "zetacoin": { "name": "Zetacoin", "canonicalName": "Zetacoin", @@ -5219,7 +4087,7 @@ "discord": "https://discord.com/invite/VRKMP2S", "networks": { "main": { - "diff1": "00000f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f", + "diff1": "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f", "solutionSize": 1344, "solutionPreambleSize": 3, "solver": { @@ -5240,7 +4108,7 @@ "saplingTxVersionGroupId": 2301567109 }, "test": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "diff1": "07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "solutionSize": 1344, "solutionPreambleSize": 3, "solver": { @@ -5261,7 +4129,7 @@ "saplingTxVersionGroupId": 2301567109 }, "regtest": { - "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "diff1": "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f", "solutionSize": 1344, "solutionPreambleSize": 3, "solver": { @@ -5816,85 +4684,6 @@ "explorerBlockLink": "https://explorer.beam.mw/block/$hash$", "explorerTxLink": "https://explorer.beam.mw/?searched_by={0}" }, - "arqma": { - "name": "ArQmA", - "symbol": "ARQ", - "family": "cryptonote", - "website": "https://arqma.com/", - "github": "https://github.com/arqma/arqma", - "market": "https://www.coingecko.com/en/coins/arqma", - "twitter": "https://twitter.com/ArQmA_Network", - "telegram": "", - "discord": "https://discord.gg/s9BQpJT", - "hash": "randomarq", - "hashVariant": 2, - "blobType": 0, - "smallestUnit": 1000000000, - "addressPrefix": 11466, - "addressPrefixStagenet": 14794, - "addressPrefixTestnet": 21450, - "addressPrefixIntegrated": 1141703, - "addressPrefixIntegratedStagenet": 1524426, - "addressPrefixIntegratedTestnet": 20554, - "subAddressPrefix": 26695, - "subAddressPrefixTestnet": 21066, - "subAddressPrefixStagenet": 1934538, - "explorerBlockLink": "https://explorer.arqma.com/block/$height$", - "explorerTxLink": "https://explorer.arqma.com/tx/{0}" - }, - "equilibria": { - "name": "Equilibria", - "symbol": "XEQ", - "family": "cryptonote", - "website": "http://equilibriacc.com/", - "github": "https://github.com/EquilibriaCC/Equilibria", - "market": "https://www.coingecko.com/en/coins/triton", - "twitter": "https://twitter.com/equilibriadevs", - "telegram": "https://t.me/XEQCommunity", - "discord": "https://discord.com/invite/kEsfkddTRu", - "hash": "randomxeq", - "hashVariant": 0, - "blobType": 5, - "smallestUnit": 10000, - "addressPrefix": 289, - "addressPrefixStagenet": 614196, - "addressPrefixTestnet": 1334, - "addressPrefixIntegrated": 25247, - "addressPrefixIntegratedStagenet": 1957684, - "addressPrefixIntegratedTestnet": 23480, - "subAddressPrefix": 22944, - "subAddressPrefixTestnet": 182, - "subAddressPrefixStagenet": 2268980, - "explorerBlockLink": "https://explorer.equilibriacc.com/block/$hash$", - "explorerTxLink": "https://explorer.equilibriacc.com/tx/{0}" - }, - "gntl": { - "name": "GNTL Coin", - "symbol": "GNTL", - "family": "cryptonote", - "website": "https://gntl.cash/", - "github": "https://github.com/The-GNTL-Project/gntl", - "market": "https://coinpaprika.com/coin/gntl-gntl", - "twitter": "https://twitter.com/GNTLCoin", - "telegram": "https://t.me/gntlcoin", - "discord": "https://discord.com/invite/4HyVA2A", - "hash": "randomarq", - "hashVariant": 2, - "blobType": 0, - "smallestUnit": 1000000000, - "addressPrefix": 504557, - "addressPrefixStagenet": 26605, - "addressPrefixTestnet": 15501, - "addressPrefixIntegrated": 1848045, - "addressPrefixIntegratedStagenet": 911341, - "addressPrefixIntegratedTestnet": 292644, - "subAddressPrefix": 2159341, - "subAddressPrefixTestnet": 3221357, - "subAddressPrefixStagenet": 616429, - "coinbaseMinConfimations": 18, - "explorerBlockLink": "https://explorer.gntl.cash/block/$hash$", - "explorerTxLink": "https://explorer.gntl.cash/tx/{0}" - }, "monero": { "name": "Monero", "canonicalName": "Monero", @@ -5920,33 +4709,6 @@ "subAddressPrefixStagenet": 36, "explorerBlockLink": "https://www.exploremonero.com/block/$height$", "explorerTxLink": "https://www.exploremonero.com/transaction/{0}" - }, - "morelo": { - "name": "Morelo", - "symbol": "MRL", - "family": "cryptonote", - "website": "https://morelonetwork.pl/", - "github": "https://github.com/MoreloNetwork/morelo", - "market": "https://coinpaprika.com/coin/mrl-morelo", - "twitter": "https://twitter.com/MoreloNetwork", - "telegram": "https://t.me/morelomrl", - "discord": "https://discord.com/invite/JB9CeFW66g", - "hash": "randomarq", - "hashVariant": 2, - "blobType": 0, - "smallestUnit": 1000000000, - "addressPrefix": 1714657, - "addressPrefixStagenet": 31586, - "addressPrefixTestnet": 525922, - "addressPrefixIntegrated": 567521, - "addressPrefixIntegratedStagenet": 1702370, - "addressPrefixIntegratedTestnet": 17762, - "subAddressPrefix": 961249, - "subAddressPrefixTestnet": 18274, - "subAddressPrefixStagenet": 2096098, - "coinbaseMinConfimations": 18, - "explorerBlockLink": "https://explorer.morelonetwork.pl/block/$hash$", - "explorerTxLink": "https://explorer.morelonetwork.pl/tx/{0}" }, "conceal": { "name": "Conceal", @@ -5979,7 +4741,7 @@ "github": "https://github.com/salvium/salvium", "market": "https://www.coingecko.com/en/coins/salvium", "twitter": "https://x.com/salvium_io", - "telegram": "", + "telegram": "https://t.me/salviumprotocol", "discord": "https://discord.com/invite/P3rrAjkyYs", "hash": "randomx", "hashVariant": 0, @@ -5997,33 +4759,6 @@ "explorerBlockLink": "https://explorer.salvium.io/block/$height$", "explorerTxLink": "https://explorer.salvium.io/tx/{0}" }, - "scala": { - "name": "Scala", - "symbol": "XLA", - "family": "cryptonote", - "website": "https://scalaproject.io/", - "github": "https://github.com/scala-network/scala", - "market": "https://www.coingecko.com/en/coins/stellite", - "twitter": "https://twitter.com/ScalaHQ", - "telegram": "", - "discord": "https://discord.gg/8PhF342", - "hash": "panthera", - "hashVariant": 3, - "blobType": 14, - "difficultyTarget": 120, - "smallestUnit": 100, - "addressPrefix": 155, - "addressPrefixTestnet": 22944, - "addressPrefixStagenet": 1188378, - "addressPrefixIntegrated": 26009, - "addressPrefixIntegratedTestnet": 22048, - "addressPrefixIntegratedStagenet": 2548250, - "subAddressPrefix": 23578, - "subAddressPrefixTestnet": 22560, - "subAddressPrefixStagenet": 2859546, - "explorerBlockLink": "https://explorer.scalaproject.io/block/$hash$", - "explorerTxLink": "https://explorer.scalaproject.io/tx/{0}" - }, "zephyr": { "name": "Zephyr", "canonicalName": "Zephyr", @@ -6049,6 +4784,34 @@ "subAddressPrefixStagenet": 249515585, "explorerBlockLink": "https://explorer.zephyrprotocol.com/block/$height$", "explorerTxLink": "https://explorer.zephyrprotocol.com/tx/{0}" + }, + "zano": { + "name": "Zano", + "canonicalName": "Zano", + "symbol": "ZANO", + "family": "zano", + "website": "https://zano.org/", + "market": "https://www.coingecko.com/en/coins/zano", + "twitter": "https://twitter.com/zano_project", + "telegram": "https://t.me/zanocoin", + "discord": "https://discord.gg/wE3rmYY", + "hash": "progpowz", + "hashVariant": 2, + "blobType": 0, + "difficultyTarget": 120, + "smallestUnit": 1000000000000, + "addressPrefix": 197, + "addressPrefixTestnet": 197, + "addressPrefixIntegrated": 13944, + "addressPrefixIntegratedTestnet": 13944, + "addressV2PrefixIntegrated": 14072, + "addressV2PrefixIntegratedTestnet": 14072, + "auditableAddressPrefix": 39112, + "auditableAddressPrefixTestnet": 39112, + "auditableAddressIntegratedPrefix": 35401, + "auditableAddressIntegratedPrefixTestnet": 35401, + "explorerBlockLink": "https://explorer.zano.org/block/$hash$", + "explorerTxLink": "https://explorer.zano.org/transaction/{0}" }, "callisto": { "name": "Callisto Network", @@ -6068,6 +4831,25 @@ "explorerAccountLink": "https://explorer.callisto.network/address/{0}", "ethasher": "ethash" }, + "cortex": { + "name": "Cortex Blockchain", + "canonicalName": "Cortex Blockchain", + "symbol": "CTXC", + "family": "ethereum", + "website": "https://www.cortexlabs.ai/", + "market": "https://www.coingecko.com/en/coins/cortex", + "twitter": "https://twitter.com/CTXCBlockchain", + "telegram": "http://t.me/CortexOfficialEN", + "discord": "", + "explorerBlockLinks": { + "block": "https://ansible.cortexlabs.ai/block/$height$", + "uncle": "https://ansible.cortexlabs.ai/block/$height$" + }, + "explorerTxLink": "https://ansible.cortexlabs.ai/tx/{0}", + "explorerAccountLink": "https://ansible.cortexlabs.ai/address/{0}", + "rpcMethodPrefix": "ctxc", + "ethasher": "ethash" + }, "ethereum": { "name": "Ethereum", "canonicalName": "Ethereum", @@ -6240,6 +5022,60 @@ "explorerTxLink": "https://explorer.alephium.org/transactions/{0}", "explorerAccountLink": "https://explorer.alephium.org/addresses/{0}" }, + "astrix-network": { + "name": "Astrix Network", + "canonicalName": "Astrix Network", + "symbol": "AIX", + "family": "kaspa", + "website": "https://astrix-network.com/", + "market": "", + "twitter": "https://x.com/astrix_network", + "telegram": "https://t.me/astrix_network", + "discord": "https://discord.gg/cwfDZJ9dHx", + "addressBech32Prefix": "astrix", + "addressBech32PrefixDevnet": "astrixdev", + "addressBech32PrefixSimnet": "astrixsim", + "addressBech32PrefixTestnet": "astrixtest", + "explorerBlockLink": "https://explorer.astrix-network.com/blocks/$hash$", + "explorerTxLink": "https://explorer.astrix-network.com/txs/{0}", + "explorerAccountLink": "https://explorer.astrix-network.com/addresses/{0}" + }, + "bitmeme": { + "name": "Bitmeme", + "canonicalName": "Bitmeme", + "symbol": "BTM", + "family": "kaspa", + "website": "https://bitmeme.site/", + "market": "https://coinmarketcap.com/currencies/kaspa/", + "twitter": "https://x.com/bitmemebtm", + "telegram": "https://t.me/bitmemebtm", + "discord": "https://discord.com/invite/f3ugpwfD", + "addressBech32Prefix": "btm", + "addressBech32PrefixDevnet": "btmdev", + "addressBech32PrefixSimnet": "btmsim", + "addressBech32PrefixTestnet": "btmtest", + "explorerBlockLink": "https://explorer.bitmeme.world/blocks/$hash$", + "explorerTxLink": "https://explorer.bitmeme.world/txs/{0}", + "explorerAccountLink": "https://explorer.bitmeme.world/addresses/{0}" + }, + "brics": { + "name": "Brics", + "canonicalName": "Brics", + "symbol": "BRICS", + "family": "kaspa", + "website": "https://bricspro.site/", + "market": "https://coinmarketcap.com/currencies/kaspa/", + "twitter": "https://x.com/BricNetwor59084", + "telegram": "https://t.me/bricsnet", + "discord": "https://discord.com/invite/f3ugpwfD", + "addressBech32Prefix": "brics", + "addressBech32PrefixDevnet": "bricsdev", + "addressBech32PrefixSimnet": "bricssim", + "addressBech32PrefixTestnet": "bricstest", + "explorerBlockLink": "https://explorer.bricspro.site/blocks/$hash$", + "explorerTxLink": "https://explorer.bricspro.site/txs/{0}", + "explorerAccountLink": "https://explorer.bricspro.site/addresses/{0}" + }, "bugna": { "name": "Bugna Network", "canonicalName": "Bugna Network", @@ -6250,10 +5086,32 @@ "twitter": "https://twitter.com/bugnanetwork", "telegram": "", "discord": "https://discord.com/invite/YxDF2EMKTq", + "addressBech32Prefix": "bugna", + "addressBech32PrefixDevnet": "bugnadev", + "addressBech32PrefixSimnet": "bugnasim", + "addressBech32PrefixTestnet": "bugnatest", "explorerBlockLink": "https://explorer.bugna.org/blocks/$hash$", "explorerTxLink": "https://explorer.bugna.org/txs/{0}", "explorerAccountLink": "https://explorer.bugna.org/addresses/{0}" }, + "consensus": { + "name": "Consensus Network", + "canonicalName": "Consensus Network", + "symbol": "CSS", + "family": "kaspa", + "website": "https://consensus-network.com/", + "market": "", + "twitter": "https://twitter.com/Consensus_CSS", + "telegram": "https://t.me/consensus_network", + "discord": "", + "addressBech32Prefix": "consensus", + "addressBech32PrefixDevnet": "consensusdev", + "addressBech32PrefixSimnet": "consensussim", + "addressBech32PrefixTestnet": "consensustest", + "explorerBlockLink": "https://explorer.consensus-network.com/blocks/$hash$", + "explorerTxLink": "https://explorer.consensus-network.com/txs/{0}", + "explorerAccountLink": "https://explorer.consensus-network.com/addresses/{0}" + }, "hoosat": { "name": "Hoosat", "canonicalName": "Hoosat", @@ -6264,6 +5122,10 @@ "twitter": "https://twitter.com/HoosatNetwork", "telegram": "https://t.me/HoosatNetwork", "discord": "https://discord.com/invite/NzENEkxEqY", + "addressBech32Prefix": "hoosat", + "addressBech32PrefixDevnet": "htndev", + "addressBech32PrefixSimnet": "hoosatsim", + "addressBech32PrefixTestnet": "hoosattest", "explorerBlockLink": "https://explorer.hoosat.fi/blocks/$hash$", "explorerTxLink": "https://explorer.hoosat.fi/txs/{0}", "explorerAccountLink": "https://explorer.hoosat.fi/addresses/{0}" @@ -6278,10 +5140,32 @@ "twitter": "https://twitter.com/KaspaCurrency", "telegram": "https://t.me/Kaspaenglish", "discord": "https://discord.gg/kS3SK5F36R", + "addressBech32Prefix": "kaspa", + "addressBech32PrefixDevnet": "kaspadev", + "addressBech32PrefixSimnet": "kaspasim", + "addressBech32PrefixTestnet": "kaspatest", "explorerBlockLink": "https://explorer.kaspa.org/blocks/$hash$", "explorerTxLink": "https://explorer.kaspa.org/txs/{0}", "explorerAccountLink": "https://explorer.kaspa.org/addresses/{0}" }, + "kaspav2": { + "name": "Kaspav2", + "canonicalName": "Kaspav2", + "symbol": "KASV2", + "family": "kaspa", + "website": "http://kaspa-v2.com/", + "market": "https://coinmarketcap.com/currencies/kaspa/", + "twitter": "https://x.com/Kaspa_v2", + "telegram": "https://t.me/kaspav2", + "discord": "https://discord.gg/kaspav2", + "addressBech32Prefix": "kasv2", + "addressBech32PrefixDevnet": "kasv2dev", + "addressBech32PrefixSimnet": "kasv2sim", + "addressBech32PrefixTestnet": "kasv2test", + "explorerBlockLink": "https://explorer.kaspa-v2.services/blocks/$hash$", + "explorerTxLink": "https://explorer.kaspa-v2.services/txs/{0}", + "explorerAccountLink": "https://explorer.kaspa-v2.services/addresses/{0}" + }, "kaspaclassic": { "name": "Kaspa Classic", "canonicalName": "Kaspa Classic", @@ -6292,6 +5176,10 @@ "twitter": "https://twitter.com/kaspaclassic", "telegram": "https://t.me/kaspaclassic", "discord": "https://discord.com/invite/kaspaclassic1", + "addressBech32Prefix": "cas", + "addressBech32PrefixDevnet": "caspadev", + "addressBech32PrefixSimnet": "pyrinsim", + "addressBech32PrefixTestnet": "pyrintest", "explorerBlockLink": "https://explorer.kaspa-classic.online/blocks/$hash$", "explorerTxLink": "https://explorer.kaspa-classic.online/txs/{0}", "explorerAccountLink": "https://explorer.kaspa-classic.online/addresses/{0}" @@ -6306,6 +5194,10 @@ "twitter": "https://twitter.com/karlsennetwork", "telegram": "https://t.me/KarlsenNetwork", "discord": "https://discord.com/invite/NasfjsEm", + "addressBech32Prefix": "karlsen", + "addressBech32PrefixDevnet": "karlsendev", + "addressBech32PrefixSimnet": "karlsensim", + "addressBech32PrefixTestnet": "karlsentest", "explorerBlockLink": "https://explorer.karlsencoin.com/blocks/$hash$", "explorerTxLink": "https://explorer.karlsencoin.com/txs/{0}", "explorerAccountLink": "https://explorer.karlsencoin.com/addresses/{0}" @@ -6320,6 +5212,10 @@ "twitter": "https://twitter.com/nautilusNTL", "telegram": "", "discord": "https://discord.com/invite/qWcUUgww4d", + "addressBech32Prefix": "nautilus", + "addressBech32PrefixDevnet": "nautiliadev", + "addressBech32PrefixSimnet": "nautilussim", + "addressBech32PrefixTestnet": "nautilustest", "explorerBlockLink": "https://explorer.nautilus-network.net/blocks/$hash$", "explorerTxLink": "https://explorer.nautilus-network.net/txs/{0}", "explorerAccountLink": "https://explorer.nautilus-network.net/addresses/{0}" @@ -6334,9 +5230,31 @@ "twitter": "https://twitter.com/nexellia", "telegram": "https://t.me/NexelliaNetwork", "discord": "https://discord.com/invite/MHn4wStC4h", - "explorerBlockLink": "https://explorer.nexell-ia.net/blocks/$hash$", - "explorerTxLink": "https://explorer.nexell-ia.net/txs/{0}", - "explorerAccountLink": "https://explorer.nexell-ia.net/addresses/{0}" + "addressBech32Prefix": "nexellia", + "addressBech32PrefixDevnet": "nexelliadev", + "addressBech32PrefixSimnet": "nexelliasim", + "addressBech32PrefixTestnet": "nexelliatest", + "explorerBlockLink": "https://explorer.nexell-ai.com/blocks/$hash$", + "explorerTxLink": "https://explorer.nexell-ai.com/txs/{0}", + "explorerAccountLink": "https://explorer.nexell-ai.com/addresses/{0}" + }, + "pugdag": { + "name": "Pugdag", + "canonicalName": "Pugdag", + "symbol": "PUG", + "family": "kaspa", + "website": "https://pugdag.com/", + "market": "", + "twitter": "https://twitter.com/pug_dag", + "telegram": "https://t.me/pug_dag", + "discord": "https://discord.com/invite/pugdag", + "addressBech32Prefix": "pugdag", + "addressBech32PrefixDevnet": "pugdagdev", + "addressBech32PrefixSimnet": "pugdagsim", + "addressBech32PrefixTestnet": "pugdagtest", + "explorerBlockLink": "https://explorer.pugdag.com/blocks/$hash$", + "explorerTxLink": "https://explorer.pugdag.com/txs/{0}", + "explorerAccountLink": "https://explorer.pugdag.com/addresses/{0}" }, "pyrin": { "name": "Pyrin", @@ -6348,6 +5266,10 @@ "twitter": "https://twitter.com/pyrin_network", "telegram": "https://t.me/pyrin_network", "discord": "https://discord.gg/QQgWRntF", + "addressBech32Prefix": "pyrin", + "addressBech32PrefixDevnet": "pyipadev", + "addressBech32PrefixSimnet": "pyrinsim", + "addressBech32PrefixTestnet": "pyrintest", "explorerBlockLink": "https://explorer.pyrin.network/blocks/$hash$", "explorerTxLink": "https://explorer.pyrin.network/txs/{0}", "explorerAccountLink": "https://explorer.pyrin.network/addresses/{0}" @@ -6362,447 +5284,59 @@ "twitter": "https://twitter.com/SedraCoin", "telegram": "https://t.me/OfficialSedraCoin", "discord": "https://discord.gg/jWHrkKMSEr", + "addressBech32Prefix": "sedra", + "addressBech32PrefixDevnet": "sedradev", + "addressBech32PrefixSimnet": "sedrasim", + "addressBech32PrefixTestnet": "sedratest", "explorerBlockLink": "https://explorer.sedracoin.com/blocks/$hash$", "explorerTxLink": "https://explorer.sedracoin.com/txs/{0}", "explorerAccountLink": "https://explorer.sedracoin.com/addresses/{0}" }, - "kobradag": { - "name": "Kobradag", - "canonicalName": "Kobradag", - "symbol": "KODA", - "family": "kaspa", - "website": "https://k0bradag.com/", - "market": "", - "twitter": "https://twitter.com/k0bradag", - "telegram": "https://t.me/k0bradag", - "discord": "https://discord.com/invite/ahnm5zENqg", - "explorerBlockLink": "https://explorer.kobradag.online/blocks/$hash$", - "explorerTxLink": "https://explorer.kobradag.online/txs/{0}", - "explorerAccountLink": "https://explorer.kobradag.online/addresses/{0}" - }, - "consensus": { - "name": "Consensus", - "canonicalName": "Consensus", - "symbol": "CSS", - "family": "kaspa", - "website": "https://consensus-network.com/", - "github": "https://github.com/consensus-network/consensusd", - "market": "", - "twitter": "https://twitter.com/Consensus_CSS", - "telegram": "https://t.me/consensus_network", - "discord": "", - "explorerBlockLink": "https://explorer.consensus-network.com/blocks/$hash$", - "explorerTxLink": "https://explorer.consensus-network.com/txs/{0}", - "explorerAccountLink": "https://explorer.consensus-network.com/addresses/{0}" - }, - "pugdag": { - "name": "Pugdag", - "canonicalName": "Pugdag", - "symbol": "PUG", + "spectre-network": { + "name": "Spectre Network", + "canonicalName": "Spectre Network", + "symbol": "SPR", "family": "kaspa", - "website": "https://pugdag.com/", - "github": "https://github.com/Pugdag/pugdagd", - "market": "https://xeggex.com/market/PUG_USDT?ref=660c7f77a13a5706f612bbc8", - "twitter": "https://twitter.com/pug_dag", - "telegram": "https://t.me/pug_dag", - "discord": "https://discord.com/invite/pugdag", - "explorerBlockLink": "https://explorer.pugdag.com/blocks/$hash$", - "explorerTxLink": "https://explorer.pugdag.com/txs/{0}", - "explorerAccountLink": "https://explorer.pugdag.com/addresses/{0}" - }, - "nvolve": { - "name": "Nvolve", - "symbol": "NVOL", - "family": "bitcoin", - "website": "https://nvolve.tech/", - "market": "https://xeggex.com/market/NVOL_USDT", - "twitter": "", - "discord": "https://discord.com/invite/NjRWrEvvV5", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "keccakc" - }, - "blockHasher": { - "hash": "reverse", - "args": [ { "hash": "sha256d" } ] - }, - "hasFounderFee": true, - "hasMasterNodes": true, - "hasSmartNodes": true, - "shareMultiplier": 256, - "explorerBlockLink": "https://explorer.nvolve.tech/block/$height$", - "explorerTxLink": "https://explorer.nvolve.tech/tx/{0}", - "explorerAccountLink": "https://explorer.nvolve.tech/address/{0}" - }, - "datromax": { - "name": "Datromax", - "symbol": "DTRX", - "family": "bitcoin", - "website": "https://datromax.com/", - "github": "https://github.com/datromax", - "twitter": "https://x.com/datromax", - "telegram": "https://t.me/datromax", - "discord": "https://discord.gg/3y2j7T3y", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "blake2s" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasFounderFee": true, - "hasMasterNodes": true, - "hasSmartNodes": true, - "explorerBlockLink": "https://explorer.datromax.com/block/$hash$", - "explorerTxLink": "https://explorer.datromax.com/tx/{0}", - "explorerAccountLink": "https://explorer.datromax.com/address/{0}" - }, - "kylacoin": { - "name": "Kylacoin", - "symbol": "KCN", - "family": "bitcoin", - "website": "https://kylacoin.com/", - "market": "https://coinpaprika.com/coin/kcn-kylacoin", - "twitter": "https://twitter.com/kylacoin", - "telegram": "https://t.me/kylacoingroup", - "discord": "https://discord.gg/SHZr5zQVDT", - "coinbaseHasher": { - "hash": "sha3-256d" - }, - "headerHasher": { - "hash": "flex" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha3-256d" - } - ] - }, - "payoutDecimalPlaces": 12, - "hasCoinbaseDevReward": true, - "explorerBlockLink": "https://kcnxp.com/block/$height$", - "explorerTxLink": "https://kcnxp.com/tx/{0}", - "explorerAccountLink": "https://kcnxp.com/address/{0}" - }, - "vkax": { - "name": "Vkax", - "symbol": "VKAX", - "family": "bitcoin", - "website": "https://vkaxcore.github.io/VKAX/", - "market": "https://www.coingecko.com/coins/vkax", - "github": "https://github.com/vkaxcore/VKAX", - "explorer": "https://explore.vkax.net/", - "twitter": "", - "telegram": "", - "discord": "https://discord.gg/AKbJJqMJ7n", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "mike" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasMasterNodes": true, - "shareMultiplier": 65536, - "coinbaseMinConfimations": 200, - "explorerBlockLink": "https://explore.vkax.net/block/$hash$", - "explorerTxLink": "https://explore.vkax.net/tx/{0}", - "explorerAccountLink": "https://explore.vkax.net/address/{0}" - }, - "akitacoin": { - "name": "Akitacoin", - "symbol": "AKIC", - "family": "progpow", - "progpower": "kawpow", - "website": "https://www.akitacoin.net/", - "github": "https://github.com/Cryptic-dev1/Akitacoin", - "market": "", - "twitter": "https://twitter.com/AkitacoinDev", - "telegram": "https://t.me/+58Y7__nzQgE1NzM0", - "discord": "https://discord.gg/juUfsDk6CS", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasCommunityAddress": true, - "shareMultiplier": 1, - "explorerBlockLink": "https://akitacoin.website/block/$hash$", - "explorerTxLink": "https://akitacoin.website/tx/{0}", - "explorerAccountLink": "https://akitacoin.website/address/{0}" - }, - "blobfish": { - "name": "Blobfish", - "symbol": "SQSH", - "family": "progpow", - "progpower": "kawpow", - "website": "https://www.blobfishcoin.meme/", - "github": "https://github.com/BFCD/blobfish", - "explorer": "https://explorer.blobfishcoin.meme/", - "market": "", - "twitter": "https://x.com/BlobfishcoinX", - "telegram": "", - "discord": "https://discord.gg/3pZ2pbUtyG", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasMasterNodes": true, - "hasPayee": true, - "shareMultiplier": 1, - "explorerBlockLink": "https://explorer.blobfishcoin.meme/block/$hash$", - "explorerTxLink": "https://explorer.blobfishcoin.meme/tx/{0}", - "explorerAccountLink": "https://explorer.blobfishcoin.meme/address/{0}" - }, - "argoneum": { - "name": "Argoneum", - "symbol": "AGM", - "family": "bitcoin", - "website": "https://argoneum.net/", - "github": "https://github.com/Argoneum/argoneum", + "website": "https://spectre-network.org/", "market": "", - "twitter": "", - "discord": "https://discordapp.com/invite/3g6XmKE", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "phi2" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "phi2" - } - ] - }, - "hasMasterNodes": true, - "shareMultiplier": 256, - "explorerBlockLink": "https://chainz.cryptoid.info/agm/block.dws?$height$.htm", - "explorerTxLink": "https://chainz.cryptoid.info/agm/tx.dws?{0}.htm", - "explorerAccountLink": "https://chainz.cryptoid.info/agm/address.dws?{0}.htm" - }, - "crionic": { - "name": "Crionic", - "canonicalName": "Crionic", - "symbol": "CRNC", - "family": "bitcoin", - "website": "https://coin.crionic.org/", - "github": "https://github.com/diabaths/Crionic-Coin", - "twitter": "", - "market": "https://coinpaprika.com/coin/crnc-crionic", - "discord": "https://discord.com/invite/SKDkjcJTKM", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "yespowerltncg" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "shareMultiplier": 65536, - "coinbaseMinConfimations": 110, - "explorerBlockLink": "https://explorer.crionic.org/block/$height$", - "explorerTxLink": "https://explorer.crionic.org/tx/{0}", - "explorerAccountLink": "https://explorer.crionic.org/address/{0}" - }, - "rincoin": { - "name": "Rincoin", - "canonicalName": "Rincoin", - "symbol": "RIN", - "family": "bitcoin", - "website": "https://coin.rin.so/", - "market": "", - "twitter": "", - "telegram": "", - "discord": "https://discord.gg/Ap7TUXYRBf", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "rinhash" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "rinhash" - } - ] - }, - "hasMWEB": true, - "diff1": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "explorerBlockLink": "https://rin-explorer.coin-miners.info/block/$hash$", - "explorerTxLink": "https://rin-explorer.coin-miners.info/tx/{0}", - "explorerAccountLink": "https://rin-explorer.coin-miners.info/address/{0}" - }, - "adventurecoin": { - "name": "AdventureCoin", - "canonicalName": "AdventureCoin", - "symbol": "ADVC", - "family": "bitcoin", - "website": "https://www.adventurecoin.quest/", - "github": "https://github.com/AdventureCoin-ADVC/AdventureCoin", - "explorer": "https://explorer.adventurecoin.quest/#/", - "twitter": "https://x.com/AdventureCoinAD", - "telegram": "https://t.me/AdventureCoinADVC", - "discord": "https://discord.gg/xNJJXqKp3T", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "yespoweradvc" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasDeveloper": true, - "shareMultiplier": 65536, - "coinbaseMinConfimations": 30, - "explorerBlockLink": "https://explorer.adventurecoin.quest/#/block/$hash$", - "explorerTxLink": "https://explorer.adventurecoin.quest/#/transaction/{0}", - "explorerAccountLink": "https://explorer.adventurecoin.quest/#/address/{0}" - }, - "evoai": { - "name": "EvoAI", - "canonicalName": "EvoAI", - "symbol": "EVO", - "family": "bitcoin", - "website": "https://evoai.top/", - "github": "https://github.com/evoai-team/evo", - "explorer": "https://explorer.evoai.top/", - "twitter": "", - "telegram": "https://t.me/+oLGorom06EllYzk1", - "discord": "https://discord.gg/9ucxz92SXN", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "evohash" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "evohash" - } - ] - }, - "coinbaseTxVersion": 8, - "coinbaseMinConfimations": 51, - "shareMultiplier": 256, - "explorerBlockLink": "https://explorer.evoai.top/block/$hash$", - "explorerTxLink": "https://explorer.evoai.top/tx/{0}", - "explorerAccountLink": "https://explorer.evoai.top/address/{0}" - }, - "lightningcashr": { - "name": "LightningCash-R", - "canonicalName": "LightningCash-R", - "symbol": "LNCR", - "family": "bitcoin", - "website": "https://lightningcash-reborn.space/", - "github": "https://github.com/MerlinMagic2018/LightningCash-R", - "twitter": "", - "market": "https://coinpaprika.com/coin/lncr-lightningcash-reborn/", - "discord": "https://discord.com/invite/WrMVXcA8bt", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "yespowerltncg" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "shareMultiplier": 65536, - "explorerBlockLink": "https://explorer.lightningcash-reborn.space/block/$height$", - "explorerTxLink": "https://explorer.lightningcash-reborn.space/tx/{0}", - "explorerAccountLink": "https://explorer.lightningcash-reborn.space/address/{0}" - }, - "privora": { - "name": "Privora", - "symbol": "VORA", - "family": "progpow", - "progpower": "firopow", - "website": "https://privora.org/", - "github": "https://github.com/PrivoraCore/Privora", - "market": "", - "twitter": "", - "telegram": "https://t.me/PrivoraTM", - "discord": "https://discord.gg/4AM5SUVzgs", - "coinbaseHasher": { - "hash": "sha256d" - }, - "headerHasher": { - "hash": "sha256d" - }, - "blockHasher": { - "hash": "reverse", - "args": [ - { - "hash": "sha256d" - } - ] - }, - "hasFounderFee": true, - "hasMasterNodes": true, - "shareMultiplier": 1, - "explorerBlockLink": "https://explorer.privora.org/block/$hash$", - "explorerTxLink": "https://explorer.privora.org/tx/{0}", - "explorerAccountLink": "https://explorer.privora.org/address/{0}" + "twitter": "https://twitter.com/SpectreNetwrk", + "telegram": "https://t.me/Spectre_Network", + "discord": "https://discord.spectre-network.org/", + "addressBech32Prefix": "spectre", + "addressBech32PrefixDevnet": "spectredev", + "addressBech32PrefixSimnet": "spectresim", + "addressBech32PrefixTestnet": "spectretest", + "hashrateMultiplier": 256, + "explorerBlockLink": "https://explorer.spectre-network.org/blocks/$hash$", + "explorerTxLink": "https://explorer.spectre-network.org/txs/{0}", + "explorerAccountLink": "https://explorer.spectre-network.org/addresses/{0}" + }, + "warthog": { + "name": "Warthog Network", + "canonicalName": "Warthog Network", + "symbol": "WART", + "family": "warthog", + "website": "https://www.warthog.network/", + "market": "https://www.coingecko.com/en/coins/warthog", + "twitter": "https://twitter.com/warthognetwork", + "telegram": "https://t.me/warthognetwork", + "discord": "https://discord.com/invite/QMDV8bGTdQ", + "explorerBlockLink": "https://wartscan.io/block/$height$", + "explorerTxLink": "https://wartscan.io/tx/{0}", + "explorerAccountLink": "https://wartscan.io/account/{0}" + }, + "xelis": { + "name": "Xelis", + "canonicalName": "Xelis", + "symbol": "XEL", + "family": "xelis", + "website": "https://xelis.io/", + "market": "https://www.coingecko.com/en/coins/xelis", + "twitter": "https://twitter.com/xelis_project", + "telegram": "https://t.me/xelis_io", + "discord": "https://discord.com/invite/z543umPUdj", + "explorerBlockLink": "https://explorer.xelis.io/blocks/$height$", + "explorerTxLink": "https://explorer.xelis.io/txs/{0}", + "explorerAccountLink": "https://explorer.xelis.io/accounts/{0}" } } diff --git a/src/Miningcore/config.schema.json b/src/Miningcore/config.schema.json index 6958c4b114..edb94bd083 100644 --- a/src/Miningcore/config.schema.json +++ b/src/Miningcore/config.schema.json @@ -558,6 +558,18 @@ }, "time": { "type": "integer" + }, + "minerEffortPercent": { + "type": [ + "number", + "null" + ] + }, + "minerEffortTime": { + "type": [ + "integer", + "null" + ] } } }, diff --git a/src/Miningcore/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs b/src/Miningcore/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs new file mode 100644 index 0000000000..ed9269506e --- /dev/null +++ b/src/Miningcore/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] diff --git a/src/Miningcore/obj/Debug/net6.0/AssemblyInfo.g.cs b/src/Miningcore/obj/Debug/net6.0/AssemblyInfo.g.cs new file mode 100644 index 0000000000..3af82a6942 --- /dev/null +++ b/src/Miningcore/obj/Debug/net6.0/AssemblyInfo.g.cs @@ -0,0 +1,13 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by GitVersion. +// +// You can modify this code as we will not overwrite it when re-executing GitVersion +// +//------------------------------------------------------------------------------ + +using System.Reflection; + +[assembly: AssemblyFileVersion("0.1.0.0")] +[assembly: AssemblyVersion("0.1.0.0")] +[assembly: AssemblyInformationalVersion("0.1.0+6.Branch.master.Sha.3804324114fe81c6321a0f8257a64d5342e9467d")] diff --git a/src/Miningcore/obj/Debug/net6.0/GitVersionInformation.g.cs b/src/Miningcore/obj/Debug/net6.0/GitVersionInformation.g.cs new file mode 100644 index 0000000000..4f6a9427ad --- /dev/null +++ b/src/Miningcore/obj/Debug/net6.0/GitVersionInformation.g.cs @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// GitVersion +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#if NET20 || NET35 || NETCOREAPP1_0 || NETCOREAPP1_1 || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 || NETSTANDARD1_3 || NETSTANDARD1_4 || NETSTANDARD1_5 || NETSTANDARD1_6 +namespace System.Diagnostics.CodeAnalysis +{ + [global::System.AttributeUsage( + global::System.AttributeTargets.Assembly | + global::System.AttributeTargets.Class | + global::System.AttributeTargets.Struct | + global::System.AttributeTargets.Constructor | + global::System.AttributeTargets.Method | + global::System.AttributeTargets.Property | + global::System.AttributeTargets.Event, + Inherited = false, AllowMultiple = false)] + internal sealed class ExcludeFromCodeCoverageAttribute : global::System.Attribute { } +} +#endif + +[global::System.Runtime.CompilerServices.CompilerGenerated] +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +static class GitVersionInformation +{ + public static string Major = "0"; + public static string Minor = "1"; + public static string Patch = "0"; + public static string PreReleaseTag = ""; + public static string PreReleaseTagWithDash = ""; + public static string PreReleaseLabel = ""; + public static string PreReleaseLabelWithDash = ""; + public static string PreReleaseNumber = ""; + public static string WeightedPreReleaseNumber = "60000"; + public static string BuildMetaData = "6"; + public static string BuildMetaDataPadded = "0006"; + public static string FullBuildMetaData = "6.Branch.master.Sha.3804324114fe81c6321a0f8257a64d5342e9467d"; + public static string MajorMinorPatch = "0.1.0"; + public static string SemVer = "0.1.0"; + public static string LegacySemVer = "0.1.0"; + public static string LegacySemVerPadded = "0.1.0"; + public static string AssemblySemVer = "0.1.0.0"; + public static string AssemblySemFileVer = "0.1.0.0"; + public static string FullSemVer = "0.1.0+6"; + public static string InformationalVersion = "0.1.0+6.Branch.master.Sha.3804324114fe81c6321a0f8257a64d5342e9467d"; + public static string BranchName = "master"; + public static string EscapedBranchName = "master"; + public static string Sha = "3804324114fe81c6321a0f8257a64d5342e9467d"; + public static string ShortSha = "3804324"; + public static string NuGetVersionV2 = "0.1.0"; + public static string NuGetVersion = "0.1.0"; + public static string NuGetPreReleaseTagV2 = ""; + public static string NuGetPreReleaseTag = ""; + public static string VersionSourceSha = "cc37fb1a6236e72c193f44f41280e0f8dc38252a"; + public static string CommitsSinceVersionSource = "6"; + public static string CommitsSinceVersionSourcePadded = "0006"; + public static string UncommittedChanges = "21"; + public static string CommitDate = "2025-03-22"; +} diff --git a/src/Miningcore/obj/Debug/net6.0/Miningcore.AssemblyInfo.cs b/src/Miningcore/obj/Debug/net6.0/Miningcore.AssemblyInfo.cs new file mode 100644 index 0000000000..b6efc34a71 --- /dev/null +++ b/src/Miningcore/obj/Debug/net6.0/Miningcore.AssemblyInfo.cs @@ -0,0 +1,21 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Miningcore.Tests")] +[assembly: System.Reflection.AssemblyCompanyAttribute("Miningcore")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyProductAttribute("Miningcore")] +[assembly: System.Reflection.AssemblyTitleAttribute("Miningcore")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/src/Miningcore/obj/Debug/net6.0/Miningcore.AssemblyInfoInputs.cache b/src/Miningcore/obj/Debug/net6.0/Miningcore.AssemblyInfoInputs.cache new file mode 100644 index 0000000000..ec1ba6a440 --- /dev/null +++ b/src/Miningcore/obj/Debug/net6.0/Miningcore.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +9b46190ae479660ef5386b6c169cea2ff394ae4b9d45b4b3920c82ad0ca294ac diff --git a/src/Miningcore/obj/Debug/net6.0/Miningcore.GeneratedMSBuildEditorConfig.editorconfig b/src/Miningcore/obj/Debug/net6.0/Miningcore.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000000..3dbe6fb9b7 --- /dev/null +++ b/src/Miningcore/obj/Debug/net6.0/Miningcore.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net6.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Miningcore +build_property.ProjectDir = C:\.Freelance\miningcore\src\Miningcore\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 6.0 +build_property.EnableCodeStyleSeverity = diff --git a/src/Miningcore/obj/Debug/net6.0/Miningcore.GlobalUsings.g.cs b/src/Miningcore/obj/Debug/net6.0/Miningcore.GlobalUsings.g.cs new file mode 100644 index 0000000000..8578f3d03d --- /dev/null +++ b/src/Miningcore/obj/Debug/net6.0/Miningcore.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/src/Miningcore/obj/Debug/net6.0/Miningcore.assets.cache b/src/Miningcore/obj/Debug/net6.0/Miningcore.assets.cache new file mode 100644 index 0000000000..d809053cd1 Binary files /dev/null and b/src/Miningcore/obj/Debug/net6.0/Miningcore.assets.cache differ diff --git a/src/Miningcore/obj/Debug/net6.0/Miningcore.csproj.AssemblyReference.cache b/src/Miningcore/obj/Debug/net6.0/Miningcore.csproj.AssemblyReference.cache new file mode 100644 index 0000000000..65b5dc3edd Binary files /dev/null and b/src/Miningcore/obj/Debug/net6.0/Miningcore.csproj.AssemblyReference.cache differ diff --git a/src/Miningcore/obj/Miningcore.csproj.nuget.dgspec.json b/src/Miningcore/obj/Miningcore.csproj.nuget.dgspec.json new file mode 100644 index 0000000000..ad5615e46c --- /dev/null +++ b/src/Miningcore/obj/Miningcore.csproj.nuget.dgspec.json @@ -0,0 +1,246 @@ +{ + "format": 1, + "restore": { + "C:\\.Freelance\\miningcore\\src\\Miningcore\\Miningcore.csproj": {} + }, + "projects": { + "C:\\.Freelance\\miningcore\\src\\Miningcore\\Miningcore.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\.Freelance\\miningcore\\src\\Miningcore\\Miningcore.csproj", + "projectName": "Miningcore", + "projectPath": "C:\\.Freelance\\miningcore\\src\\Miningcore\\Miningcore.csproj", + "packagesPath": "C:\\Users\\Jiegrein\\.nuget\\packages\\", + "outputPath": "C:\\.Freelance\\miningcore\\src\\Miningcore\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\Jiegrein\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "C:\\.CreditEnable\\Project\\CE.JourneyCRMSync.App\\local_packages": {}, + "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "AspNetCoreRateLimit": { + "target": "Package", + "version": "[5.0.0, )" + }, + "AutoMapper": { + "target": "Package", + "version": "[12.0.1, )" + }, + "Autofac": { + "target": "Package", + "version": "[8.1.0, )" + }, + "Autofac.Extensions.DependencyInjection": { + "target": "Package", + "version": "[10.0.0, )" + }, + "CircularBuffer": { + "target": "Package", + "version": "[1.4.0, )" + }, + "Dapper": { + "target": "Package", + "version": "[2.1.35, )" + }, + "FluentValidation": { + "target": "Package", + "version": "[11.10.0, )" + }, + "FluentValidation.AspNetCore": { + "target": "Package", + "version": "[11.3.0, )" + }, + "FluentValidation.DependencyInjectionExtensions": { + "target": "Package", + "version": "[11.10.0, )" + }, + "GitVersion.MsBuild": { + "include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive", + "suppressParent": "All", + "target": "Package", + "version": "[5.12.0, )" + }, + "Google.Protobuf": { + "target": "Package", + "version": "[3.26.1, )" + }, + "Grpc.AspNetCore": { + "target": "Package", + "version": "[2.57.0, )" + }, + "Grpc.Net.Client": { + "target": "Package", + "version": "[2.62.0, )" + }, + "Grpc.Tools": { + "include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive", + "suppressParent": "All", + "target": "Package", + "version": "[2.62.0, )" + }, + "JetBrains.Annotations": { + "target": "Package", + "version": "[2024.3.0, )" + }, + "MailKit": { + "target": "Package", + "version": "[3.5.0, )" + }, + "McMaster.Extensions.CommandLineUtils": { + "target": "Package", + "version": "[4.0.2, )" + }, + "Microsoft.Extensions.Caching.Memory": { + "target": "Package", + "version": "[8.0.1, )" + }, + "Microsoft.Extensions.Configuration.Json": { + "target": "Package", + "version": "[8.0.0, )" + }, + "Microsoft.Extensions.Options.ConfigurationExtensions": { + "target": "Package", + "version": "[8.0.0, )" + }, + "Microsoft.IO.RecyclableMemoryStream": { + "target": "Package", + "version": "[3.0.0, )" + }, + "NBitcoin": { + "target": "Package", + "version": "[7.0.42, )" + }, + "NBitcoin.Altcoins": { + "target": "Package", + "version": "[3.0.28, )" + }, + "NBitcoin.Secp256k1": { + "target": "Package", + "version": "[3.1.6, )" + }, + "NBitcoin.Zcash": { + "target": "Package", + "version": "[3.0.0, )" + }, + "NLog": { + "target": "Package", + "version": "[5.3.4, )" + }, + "NLog.Extensions.Hosting": { + "target": "Package", + "version": "[5.3.8, )" + }, + "NLog.Extensions.Logging": { + "target": "Package", + "version": "[5.3.14, )" + }, + "NSwag.AspNetCore": { + "target": "Package", + "version": "[14.0.2, )" + }, + "NSwag.CodeGeneration.CSharp": { + "target": "Package", + "version": "[14.0.2, )" + }, + "NSwag.MSBuild": { + "include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive", + "suppressParent": "All", + "target": "Package", + "version": "[14.0.2, )" + }, + "Newtonsoft.Json": { + "target": "Package", + "version": "[13.0.3, )" + }, + "Newtonsoft.Json.Schema": { + "target": "Package", + "version": "[4.0.1, )" + }, + "Npgsql": { + "target": "Package", + "version": "[8.0.5, )" + }, + "Polly": { + "target": "Package", + "version": "[8.3.1, )" + }, + "Portable.BouncyCastle": { + "target": "Package", + "version": "[1.9.0, )" + }, + "System.Diagnostics.Process": { + "target": "Package", + "version": "[4.3.0, )" + }, + "System.Reactive": { + "target": "Package", + "version": "[6.0.0, )" + }, + "prometheus-net": { + "target": "Package", + "version": "[8.2.0, )" + }, + "prometheus-net.AspNetCore": { + "target": "Package", + "version": "[8.1.0, )" + }, + "protobuf-net": { + "target": "Package", + "version": "[3.2.30, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.101\\RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/src/Miningcore/obj/Miningcore.csproj.nuget.g.props b/src/Miningcore/obj/Miningcore.csproj.nuget.g.props new file mode 100644 index 0000000000..4e73667522 --- /dev/null +++ b/src/Miningcore/obj/Miningcore.csproj.nuget.g.props @@ -0,0 +1,29 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + $(UserProfile)\.nuget\packages\ + C:\Users\Jiegrein\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages + PackageReference + 6.12.2 + + + + + + + + + + + + + + C:\Users\Jiegrein\.nuget\packages\nswag.msbuild\14.0.2 + C:\Users\Jiegrein\.nuget\packages\microsoft.extensions.apidescription.server\6.0.3 + C:\Users\Jiegrein\.nuget\packages\grpc.tools\2.62.0 + C:\Users\Jiegrein\.nuget\packages\gitversion.msbuild\5.12.0 + + \ No newline at end of file diff --git a/src/Miningcore/obj/Miningcore.csproj.nuget.g.targets b/src/Miningcore/obj/Miningcore.csproj.nuget.g.targets new file mode 100644 index 0000000000..d1c7cf56d1 --- /dev/null +++ b/src/Miningcore/obj/Miningcore.csproj.nuget.g.targets @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Miningcore/obj/gitversion.json b/src/Miningcore/obj/gitversion.json new file mode 100644 index 0000000000..92ef4eee9b --- /dev/null +++ b/src/Miningcore/obj/gitversion.json @@ -0,0 +1,35 @@ +{ + "Major": 0, + "Minor": 1, + "Patch": 0, + "PreReleaseTag": "", + "PreReleaseTagWithDash": "", + "PreReleaseLabel": "", + "PreReleaseLabelWithDash": "", + "PreReleaseNumber": null, + "WeightedPreReleaseNumber": 60000, + "BuildMetaData": 6, + "BuildMetaDataPadded": "0006", + "FullBuildMetaData": "6.Branch.master.Sha.3804324114fe81c6321a0f8257a64d5342e9467d", + "MajorMinorPatch": "0.1.0", + "SemVer": "0.1.0", + "LegacySemVer": "0.1.0", + "LegacySemVerPadded": "0.1.0", + "AssemblySemVer": "0.1.0.0", + "AssemblySemFileVer": "0.1.0.0", + "FullSemVer": "0.1.0+6", + "InformationalVersion": "0.1.0+6.Branch.master.Sha.3804324114fe81c6321a0f8257a64d5342e9467d", + "BranchName": "master", + "EscapedBranchName": "master", + "Sha": "3804324114fe81c6321a0f8257a64d5342e9467d", + "ShortSha": "3804324", + "NuGetVersionV2": "0.1.0", + "NuGetVersion": "0.1.0", + "NuGetPreReleaseTagV2": "", + "NuGetPreReleaseTag": "", + "VersionSourceSha": "cc37fb1a6236e72c193f44f41280e0f8dc38252a", + "CommitsSinceVersionSource": 6, + "CommitsSinceVersionSourcePadded": "0006", + "UncommittedChanges": 21, + "CommitDate": "2025-03-22" +} \ No newline at end of file diff --git a/src/Miningcore/obj/project.assets.json b/src/Miningcore/obj/project.assets.json new file mode 100644 index 0000000000..7e01841523 --- /dev/null +++ b/src/Miningcore/obj/project.assets.json @@ -0,0 +1,6949 @@ +{ + "version": 3, + "targets": { + "net6.0": { + "AspNetCoreRateLimit/5.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "6.0.0", + "Microsoft.Extensions.Logging.Abstractions": "6.0.3", + "Microsoft.Extensions.Options": "6.0.0", + "Newtonsoft.Json": "13.0.2" + }, + "compile": { + "lib/net6.0/AspNetCoreRateLimit.dll": {} + }, + "runtime": { + "lib/net6.0/AspNetCoreRateLimit.dll": {} + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ] + }, + "Autofac/8.1.0": { + "type": "package", + "dependencies": { + "System.Diagnostics.DiagnosticSource": "8.0.1" + }, + "compile": { + "lib/net6.0/Autofac.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Autofac.dll": { + "related": ".xml" + } + } + }, + "Autofac.Extensions.DependencyInjection/10.0.0": { + "type": "package", + "dependencies": { + "Autofac": "8.1.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1" + }, + "compile": { + "lib/net6.0/Autofac.Extensions.DependencyInjection.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Autofac.Extensions.DependencyInjection.dll": { + "related": ".xml" + } + } + }, + "AutoMapper/12.0.1": { + "type": "package", + "dependencies": { + "Microsoft.CSharp": "4.7.0" + }, + "compile": { + "lib/netstandard2.1/AutoMapper.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.1/AutoMapper.dll": { + "related": ".xml" + } + } + }, + "CircularBuffer/1.4.0": { + "type": "package", + "compile": { + "lib/net6.0/CircularBuffer.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/CircularBuffer.dll": { + "related": ".xml" + } + } + }, + "Dapper/2.1.35": { + "type": "package", + "compile": { + "lib/net5.0/Dapper.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/Dapper.dll": { + "related": ".xml" + } + } + }, + "FluentValidation/11.10.0": { + "type": "package", + "compile": { + "lib/net6.0/FluentValidation.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/FluentValidation.dll": { + "related": ".xml" + } + } + }, + "FluentValidation.AspNetCore/11.3.0": { + "type": "package", + "dependencies": { + "FluentValidation": "11.5.1", + "FluentValidation.DependencyInjectionExtensions": "11.5.1" + }, + "compile": { + "lib/net6.0/FluentValidation.AspNetCore.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/FluentValidation.AspNetCore.dll": { + "related": ".xml" + } + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ] + }, + "FluentValidation.DependencyInjectionExtensions/11.10.0": { + "type": "package", + "dependencies": { + "FluentValidation": "11.10.0", + "Microsoft.Extensions.Dependencyinjection.Abstractions": "2.1.0" + }, + "compile": { + "lib/netstandard2.1/FluentValidation.DependencyInjectionExtensions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.1/FluentValidation.DependencyInjectionExtensions.dll": { + "related": ".xml" + } + } + }, + "Fluid.Core/2.5.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "1.1.1", + "Parlot": "0.0.24", + "TimeZoneConverter": "6.0.1" + }, + "compile": { + "lib/net6.0/Fluid.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/net6.0/Fluid.dll": { + "related": ".pdb;.xml" + } + } + }, + "GitVersion.MsBuild/5.12.0": { + "type": "package", + "build": { + "build/GitVersion.MsBuild.props": {}, + "build/GitVersion.MsBuild.targets": {} + }, + "buildMultiTargeting": { + "buildMultiTargeting/GitVersion.MsBuild.props": {}, + "buildMultiTargeting/GitVersion.MsBuild.targets": {} + } + }, + "Google.Protobuf/3.26.1": { + "type": "package", + "compile": { + "lib/net5.0/Google.Protobuf.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/net5.0/Google.Protobuf.dll": { + "related": ".pdb;.xml" + } + } + }, + "Grpc.AspNetCore/2.57.0": { + "type": "package", + "dependencies": { + "Google.Protobuf": "3.23.1", + "Grpc.AspNetCore.Server.ClientFactory": "2.57.0", + "Grpc.Tools": "2.57.0" + }, + "compile": { + "lib/net6.0/_._": {} + }, + "runtime": { + "lib/net6.0/_._": {} + } + }, + "Grpc.AspNetCore.Server/2.57.0": { + "type": "package", + "dependencies": { + "Grpc.Net.Common": "2.57.0" + }, + "compile": { + "lib/net6.0/Grpc.AspNetCore.Server.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/net6.0/Grpc.AspNetCore.Server.dll": { + "related": ".pdb;.xml" + } + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ] + }, + "Grpc.AspNetCore.Server.ClientFactory/2.57.0": { + "type": "package", + "dependencies": { + "Grpc.AspNetCore.Server": "2.57.0", + "Grpc.Net.ClientFactory": "2.57.0" + }, + "compile": { + "lib/net6.0/Grpc.AspNetCore.Server.ClientFactory.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/net6.0/Grpc.AspNetCore.Server.ClientFactory.dll": { + "related": ".pdb;.xml" + } + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ] + }, + "Grpc.Core.Api/2.62.0": { + "type": "package", + "compile": { + "lib/netstandard2.1/Grpc.Core.Api.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/netstandard2.1/Grpc.Core.Api.dll": { + "related": ".pdb;.xml" + } + } + }, + "Grpc.Net.Client/2.62.0": { + "type": "package", + "dependencies": { + "Grpc.Net.Common": "2.62.0", + "Microsoft.Extensions.Logging.Abstractions": "6.0.0" + }, + "compile": { + "lib/net6.0/Grpc.Net.Client.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/net6.0/Grpc.Net.Client.dll": { + "related": ".pdb;.xml" + } + } + }, + "Grpc.Net.ClientFactory/2.57.0": { + "type": "package", + "dependencies": { + "Grpc.Net.Client": "2.57.0", + "Microsoft.Extensions.Http": "6.0.0" + }, + "compile": { + "lib/net6.0/Grpc.Net.ClientFactory.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/net6.0/Grpc.Net.ClientFactory.dll": { + "related": ".pdb;.xml" + } + } + }, + "Grpc.Net.Common/2.62.0": { + "type": "package", + "dependencies": { + "Grpc.Core.Api": "2.62.0" + }, + "compile": { + "lib/net6.0/Grpc.Net.Common.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/net6.0/Grpc.Net.Common.dll": { + "related": ".pdb;.xml" + } + } + }, + "Grpc.Tools/2.62.0": { + "type": "package", + "build": { + "build/Grpc.Tools.props": {}, + "build/Grpc.Tools.targets": {} + } + }, + "JetBrains.Annotations/2024.3.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/JetBrains.Annotations.dll": { + "related": ".deps.json;.xml" + } + }, + "runtime": { + "lib/netstandard2.0/JetBrains.Annotations.dll": { + "related": ".deps.json;.xml" + } + } + }, + "MailKit/3.5.0": { + "type": "package", + "dependencies": { + "MimeKit": "3.5.0" + }, + "compile": { + "lib/net6.0/MailKit.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/net6.0/MailKit.dll": { + "related": ".pdb;.xml" + } + } + }, + "McMaster.Extensions.CommandLineUtils/4.0.2": { + "type": "package", + "dependencies": { + "System.ComponentModel.Annotations": "5.0.0" + }, + "compile": { + "lib/netstandard2.1/McMaster.Extensions.CommandLineUtils.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.1/McMaster.Extensions.CommandLineUtils.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Bcl.AsyncInterfaces/6.0.0": { + "type": "package", + "compile": { + "lib/netstandard2.1/Microsoft.Bcl.AsyncInterfaces.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.1/Microsoft.Bcl.AsyncInterfaces.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Bcl.TimeProvider/8.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.Bcl.TimeProvider.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Bcl.TimeProvider.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.CSharp/4.7.0": { + "type": "package", + "compile": { + "ref/netcoreapp2.0/_._": {} + }, + "runtime": { + "lib/netcoreapp2.0/_._": {} + } + }, + "Microsoft.Extensions.ApiDescription.Server/6.0.3": { + "type": "package", + "build": { + "build/Microsoft.Extensions.ApiDescription.Server.props": {}, + "build/Microsoft.Extensions.ApiDescription.Server.targets": {} + }, + "buildMultiTargeting": { + "buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.props": {}, + "buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.targets": {} + } + }, + "Microsoft.Extensions.Caching.Abstractions/8.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Caching.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Caching.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Caching.Memory/8.0.1": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "8.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2", + "Microsoft.Extensions.Logging.Abstractions": "8.0.2", + "Microsoft.Extensions.Options": "8.0.2", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Caching.Memory.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Caching.Memory.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Configuration.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Configuration.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Configuration.Binder/8.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Configuration.Binder.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Configuration.Binder.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/netstandard2.0/Microsoft.Extensions.Configuration.Binder.targets": {} + } + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "System.Text.Json": "8.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Configuration.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Configuration.Json.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.DependencyInjection/6.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/netcoreapp3.1/_._": {} + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.2": { + "type": "package", + "compile": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.FileProviders.Embedded/6.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.FileProviders.Embedded.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.FileProviders.Embedded.dll": { + "related": ".xml" + } + }, + "build": { + "build/netstandard2.0/_._": {} + }, + "buildMultiTargeting": { + "buildMultiTargeting/_._": {} + } + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "type": "package", + "compile": { + "lib/net6.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Hosting.Abstractions/6.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0" + }, + "compile": { + "lib/netstandard2.1/Microsoft.Extensions.Hosting.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.1/Microsoft.Extensions.Hosting.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Http/6.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "Microsoft.Extensions.Logging": "6.0.0", + "Microsoft.Extensions.Logging.Abstractions": "6.0.0", + "Microsoft.Extensions.Options": "6.0.0" + }, + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Http.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Http.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Logging/6.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "6.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "Microsoft.Extensions.Logging.Abstractions": "6.0.0", + "Microsoft.Extensions.Options": "6.0.0", + "System.Diagnostics.DiagnosticSource": "6.0.0" + }, + "compile": { + "lib/netstandard2.1/Microsoft.Extensions.Logging.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.1/Microsoft.Extensions.Logging.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/8.0.2": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2", + "System.Diagnostics.DiagnosticSource": "8.0.1" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets": {} + } + }, + "Microsoft.Extensions.ObjectPool/7.0.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.ObjectPool.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.ObjectPool.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Options/8.0.2": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Options.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Options.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/Microsoft.Extensions.Options.targets": {} + } + }, + "Microsoft.Extensions.Options.ConfigurationExtensions/8.0.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.Binder": "8.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Options.ConfigurationExtensions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Options.ConfigurationExtensions.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + }, + "compile": { + "lib/net6.0/Microsoft.Extensions.Primitives.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.Primitives.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "Microsoft.IO.RecyclableMemoryStream/3.0.0": { + "type": "package", + "compile": { + "lib/net6.0/Microsoft.IO.RecyclableMemoryStream.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Microsoft.IO.RecyclableMemoryStream.dll": { + "related": ".xml" + } + } + }, + "Microsoft.NETCore.Platforms/1.1.0": { + "type": "package", + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "Microsoft.NETCore.Targets/1.1.0": { + "type": "package", + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "Microsoft.Win32.Primitives/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + }, + "compile": { + "ref/netstandard1.3/_._": { + "related": ".xml" + } + } + }, + "Microsoft.Win32.Registry/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0" + }, + "compile": { + "ref/netstandard1.3/_._": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/unix/lib/netstandard1.3/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netstandard1.3/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "MimeKit/3.5.0": { + "type": "package", + "dependencies": { + "Portable.BouncyCastle": "1.9.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0", + "System.Security.Cryptography.Pkcs": "6.0.0", + "System.Text.Encoding.CodePages": "6.0.0" + }, + "compile": { + "lib/net6.0/MimeKit.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/net6.0/MimeKit.dll": { + "related": ".pdb;.xml" + } + } + }, + "Namotion.Reflection/3.1.1": { + "type": "package", + "dependencies": { + "Microsoft.CSharp": "4.3.0" + }, + "compile": { + "lib/netstandard2.0/Namotion.Reflection.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Namotion.Reflection.dll": { + "related": ".xml" + } + } + }, + "NBitcoin/7.0.42": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "1.0.0", + "Newtonsoft.Json": "13.0.1" + }, + "compile": { + "lib/net6.0/NBitcoin.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/NBitcoin.dll": { + "related": ".xml" + } + } + }, + "NBitcoin.Altcoins/3.0.28": { + "type": "package", + "dependencies": { + "NBitcoin": "7.0.42" + }, + "compile": { + "lib/net6.0/NBitcoin.Altcoins.dll": {} + }, + "runtime": { + "lib/net6.0/NBitcoin.Altcoins.dll": {} + } + }, + "NBitcoin.Secp256k1/3.1.6": { + "type": "package", + "compile": { + "lib/net6.0/NBitcoin.Secp256k1.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/NBitcoin.Secp256k1.dll": { + "related": ".xml" + } + } + }, + "NBitcoin.Zcash/3.0.0": { + "type": "package", + "dependencies": { + "NBitcoin": "4.1.1.45", + "Portable.BouncyCastle": "1.8.2" + }, + "compile": { + "lib/netstandard2.0/NBitcoin.Zcash.dll": {} + }, + "runtime": { + "lib/netstandard2.0/NBitcoin.Zcash.dll": {} + } + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "Newtonsoft.Json.Schema/4.0.1": { + "type": "package", + "dependencies": { + "Newtonsoft.Json": "13.0.3" + }, + "compile": { + "lib/netstandard2.1/Newtonsoft.Json.Schema.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.1/Newtonsoft.Json.Schema.dll": { + "related": ".xml" + } + } + }, + "NJsonSchema/11.0.0": { + "type": "package", + "dependencies": { + "NJsonSchema.Annotations": "11.0.0", + "Namotion.Reflection": "3.1.1", + "Newtonsoft.Json": "13.0.3" + }, + "compile": { + "lib/net6.0/NJsonSchema.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/NJsonSchema.dll": { + "related": ".xml" + } + } + }, + "NJsonSchema.Annotations/11.0.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/NJsonSchema.Annotations.dll": {} + }, + "runtime": { + "lib/netstandard2.0/NJsonSchema.Annotations.dll": {} + } + }, + "NJsonSchema.CodeGeneration/11.0.0": { + "type": "package", + "dependencies": { + "Fluid.Core": "2.5.0", + "NJsonSchema": "11.0.0" + }, + "compile": { + "lib/netstandard2.0/NJsonSchema.CodeGeneration.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/NJsonSchema.CodeGeneration.dll": { + "related": ".xml" + } + } + }, + "NJsonSchema.CodeGeneration.CSharp/11.0.0": { + "type": "package", + "dependencies": { + "NJsonSchema.CodeGeneration": "11.0.0" + }, + "compile": { + "lib/netstandard2.0/NJsonSchema.CodeGeneration.CSharp.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/NJsonSchema.CodeGeneration.CSharp.dll": { + "related": ".xml" + } + } + }, + "NJsonSchema.NewtonsoftJson/11.0.0": { + "type": "package", + "dependencies": { + "NJsonSchema": "11.0.0", + "Newtonsoft.Json": "13.0.3" + }, + "compile": { + "lib/netstandard2.0/NJsonSchema.NewtonsoftJson.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/NJsonSchema.NewtonsoftJson.dll": { + "related": ".xml" + } + } + }, + "NJsonSchema.Yaml/11.0.0": { + "type": "package", + "dependencies": { + "NJsonSchema": "11.0.0", + "YamlDotNet": "13.7.1" + }, + "compile": { + "lib/netstandard2.0/NJsonSchema.Yaml.dll": {} + }, + "runtime": { + "lib/netstandard2.0/NJsonSchema.Yaml.dll": {} + } + }, + "NLog/5.3.4": { + "type": "package", + "compile": { + "lib/netstandard2.0/NLog.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/NLog.dll": { + "related": ".xml" + } + } + }, + "NLog.Extensions.Hosting/5.3.8": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Hosting.Abstractions": "6.0.0", + "NLog.Extensions.Logging": "5.3.8" + }, + "compile": { + "lib/net6.0/NLog.Extensions.Hosting.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/NLog.Extensions.Hosting.dll": { + "related": ".xml" + } + } + }, + "NLog.Extensions.Logging/5.3.14": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", + "Microsoft.Extensions.Logging": "6.0.0", + "NLog": "5.3.4" + }, + "compile": { + "lib/net6.0/NLog.Extensions.Logging.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/NLog.Extensions.Logging.dll": { + "related": ".xml" + } + } + }, + "Npgsql/8.0.5": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "System.Diagnostics.DiagnosticSource": "8.0.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0", + "System.Text.Json": "8.0.5" + }, + "compile": { + "lib/net6.0/Npgsql.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Npgsql.dll": { + "related": ".xml" + } + } + }, + "NSwag.Annotations/14.0.2": { + "type": "package", + "compile": { + "lib/netstandard2.0/NSwag.Annotations.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/NSwag.Annotations.dll": { + "related": ".xml" + } + } + }, + "NSwag.AspNetCore/14.0.2": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.ApiDescription.Server": "6.0.3", + "Microsoft.Extensions.FileProviders.Embedded": "6.0.0", + "NSwag.Annotations": "14.0.2", + "NSwag.Core": "14.0.2", + "NSwag.Core.Yaml": "14.0.2", + "NSwag.Generation": "14.0.2", + "NSwag.Generation.AspNetCore": "14.0.2" + }, + "compile": { + "lib/net6.0/NSwag.AspNetCore.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/NSwag.AspNetCore.dll": { + "related": ".xml" + } + }, + "build": { + "build/NSwag.AspNetCore.props": {}, + "build/NSwag.AspNetCore.targets": {} + }, + "buildMultiTargeting": { + "buildMultiTargeting/NSwag.AspNetCore.props": {}, + "buildMultiTargeting/NSwag.AspNetCore.targets": {} + } + }, + "NSwag.CodeGeneration/14.0.2": { + "type": "package", + "dependencies": { + "NJsonSchema.CodeGeneration": "11.0.0", + "NSwag.Core": "14.0.2" + }, + "compile": { + "lib/netstandard2.0/NSwag.CodeGeneration.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/NSwag.CodeGeneration.dll": { + "related": ".xml" + } + } + }, + "NSwag.CodeGeneration.CSharp/14.0.2": { + "type": "package", + "dependencies": { + "NJsonSchema.CodeGeneration.CSharp": "11.0.0", + "NSwag.CodeGeneration": "14.0.2" + }, + "compile": { + "lib/netstandard2.0/NSwag.CodeGeneration.CSharp.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/NSwag.CodeGeneration.CSharp.dll": { + "related": ".xml" + } + } + }, + "NSwag.Core/14.0.2": { + "type": "package", + "dependencies": { + "NJsonSchema": "11.0.0" + }, + "compile": { + "lib/netstandard2.0/NSwag.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/NSwag.Core.dll": { + "related": ".xml" + } + } + }, + "NSwag.Core.Yaml/14.0.2": { + "type": "package", + "dependencies": { + "NJsonSchema.Yaml": "11.0.0", + "NSwag.Core": "14.0.2" + }, + "compile": { + "lib/netstandard2.0/NSwag.Core.Yaml.dll": {} + }, + "runtime": { + "lib/netstandard2.0/NSwag.Core.Yaml.dll": {} + } + }, + "NSwag.Generation/14.0.2": { + "type": "package", + "dependencies": { + "NJsonSchema.NewtonsoftJson": "11.0.0", + "NSwag.Core": "14.0.2" + }, + "compile": { + "lib/netstandard2.0/NSwag.Generation.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/NSwag.Generation.dll": { + "related": ".xml" + } + } + }, + "NSwag.Generation.AspNetCore/14.0.2": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "Microsoft.Extensions.Options": "6.0.0", + "NSwag.Generation": "14.0.2" + }, + "compile": { + "lib/net6.0/NSwag.Generation.AspNetCore.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/NSwag.Generation.AspNetCore.dll": { + "related": ".xml" + } + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ] + }, + "NSwag.MSBuild/14.0.2": { + "type": "package", + "build": { + "buildTransitive/NSwag.MSBuild.props": {} + }, + "buildMultiTargeting": { + "buildCrossTargeting/NSwag.MSBuild.props": {} + } + }, + "Parlot/0.0.24": { + "type": "package", + "compile": { + "lib/netstandard2.1/Parlot.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.1/Parlot.dll": { + "related": ".xml" + } + } + }, + "Polly/8.3.1": { + "type": "package", + "dependencies": { + "Polly.Core": "8.3.1" + }, + "compile": { + "lib/net6.0/Polly.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/net6.0/Polly.dll": { + "related": ".pdb;.xml" + } + } + }, + "Polly.Core/8.3.1": { + "type": "package", + "dependencies": { + "Microsoft.Bcl.TimeProvider": "8.0.0" + }, + "compile": { + "lib/net6.0/Polly.Core.dll": { + "related": ".pdb;.xml" + } + }, + "runtime": { + "lib/net6.0/Polly.Core.dll": { + "related": ".pdb;.xml" + } + } + }, + "Portable.BouncyCastle/1.9.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/BouncyCastle.Crypto.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/BouncyCastle.Crypto.dll": { + "related": ".xml" + } + } + }, + "prometheus-net/8.2.0": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.Http": "3.1.0", + "Microsoft.Extensions.ObjectPool": "7.0.0" + }, + "compile": { + "lib/net6.0/Prometheus.NetStandard.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Prometheus.NetStandard.dll": { + "related": ".xml" + } + } + }, + "prometheus-net.AspNetCore/8.1.0": { + "type": "package", + "dependencies": { + "prometheus-net": "8.1.0" + }, + "compile": { + "lib/net6.0/Prometheus.AspNetCore.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Prometheus.AspNetCore.dll": { + "related": ".xml" + } + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ] + }, + "protobuf-net/3.2.30": { + "type": "package", + "dependencies": { + "protobuf-net.Core": "3.2.30" + }, + "compile": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + } + }, + "protobuf-net.Core/3.2.30": { + "type": "package", + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "compile": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + } + }, + "runtime.native.System/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + }, + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "System.Collections/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + }, + "compile": { + "ref/netstandard1.3/_._": { + "related": ".xml" + } + } + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + }, + "compile": { + "lib/net6.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.ComponentModel.Annotations/5.0.0": { + "type": "package", + "compile": { + "ref/netstandard2.1/System.ComponentModel.Annotations.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.1/System.ComponentModel.Annotations.dll": { + "related": ".xml" + } + } + }, + "System.Diagnostics.Debug/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + }, + "compile": { + "ref/netstandard1.3/_._": { + "related": ".xml" + } + } + }, + "System.Diagnostics.DiagnosticSource/8.0.1": { + "type": "package", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + }, + "compile": { + "lib/net6.0/System.Diagnostics.DiagnosticSource.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/System.Diagnostics.DiagnosticSource.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.Diagnostics.Process/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.Win32.Primitives": "4.3.0", + "Microsoft.Win32.Registry": "4.3.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "System.Threading.Thread": "4.3.0", + "System.Threading.ThreadPool": "4.3.0", + "runtime.native.System": "4.3.0" + }, + "compile": { + "ref/netstandard1.4/System.Diagnostics.Process.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/linux/lib/netstandard1.4/System.Diagnostics.Process.dll": { + "assetType": "runtime", + "rid": "linux" + }, + "runtimes/osx/lib/netstandard1.4/System.Diagnostics.Process.dll": { + "assetType": "runtime", + "rid": "osx" + }, + "runtimes/win/lib/netstandard1.4/System.Diagnostics.Process.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Formats.Asn1/6.0.0": { + "type": "package", + "compile": { + "lib/net6.0/System.Formats.Asn1.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/System.Formats.Asn1.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/netcoreapp3.1/_._": {} + } + }, + "System.Globalization/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + }, + "compile": { + "ref/netstandard1.3/_._": { + "related": ".xml" + } + } + }, + "System.IO/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + }, + "compile": { + "ref/netstandard1.5/System.IO.dll": { + "related": ".xml" + } + } + }, + "System.IO.FileSystem/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + }, + "compile": { + "ref/netstandard1.3/_._": { + "related": ".xml" + } + } + }, + "System.IO.FileSystem.Primitives/4.3.0": { + "type": "package", + "dependencies": { + "System.Runtime": "4.3.0" + }, + "compile": { + "ref/netstandard1.3/_._": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard1.3/System.IO.FileSystem.Primitives.dll": {} + } + }, + "System.Reactive/6.0.0": { + "type": "package", + "compile": { + "lib/net6.0/System.Reactive.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/System.Reactive.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.Reflection/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + }, + "compile": { + "ref/netstandard1.5/_._": { + "related": ".xml" + } + } + }, + "System.Reflection.Primitives/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + }, + "compile": { + "ref/netstandard1.0/_._": { + "related": ".xml" + } + } + }, + "System.Resources.ResourceManager/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + }, + "compile": { + "ref/netstandard1.0/_._": { + "related": ".xml" + } + } + }, + "System.Runtime/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + }, + "compile": { + "ref/netstandard1.5/System.Runtime.dll": { + "related": ".xml" + } + } + }, + "System.Runtime.CompilerServices.Unsafe/6.0.0": { + "type": "package", + "compile": { + "lib/net6.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/netcoreapp3.1/_._": {} + } + }, + "System.Runtime.Extensions/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + }, + "compile": { + "ref/netstandard1.5/_._": { + "related": ".xml" + } + } + }, + "System.Runtime.Handles/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + }, + "compile": { + "ref/netstandard1.3/System.Runtime.Handles.dll": { + "related": ".xml" + } + } + }, + "System.Runtime.InteropServices/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + }, + "compile": { + "ref/netcoreapp1.1/_._": {} + } + }, + "System.Security.Cryptography.Pkcs/6.0.0": { + "type": "package", + "dependencies": { + "System.Formats.Asn1": "6.0.0" + }, + "compile": { + "lib/net6.0/System.Security.Cryptography.Pkcs.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/System.Security.Cryptography.Pkcs.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/netcoreapp3.1/_._": {} + }, + "runtimeTargets": { + "runtimes/win/lib/net6.0/System.Security.Cryptography.Pkcs.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Text.Encoding/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + }, + "compile": { + "ref/netstandard1.3/System.Text.Encoding.dll": { + "related": ".xml" + } + } + }, + "System.Text.Encoding.CodePages/6.0.0": { + "type": "package", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + }, + "compile": { + "lib/net6.0/System.Text.Encoding.CodePages.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/System.Text.Encoding.CodePages.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/netcoreapp3.1/_._": {} + }, + "runtimeTargets": { + "runtimes/win/lib/net6.0/System.Text.Encoding.CodePages.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Text.Encoding.Extensions/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0" + }, + "compile": { + "ref/netstandard1.3/_._": { + "related": ".xml" + } + } + }, + "System.Text.Encodings.Web/8.0.0": { + "type": "package", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + }, + "compile": { + "lib/net6.0/System.Text.Encodings.Web.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/System.Text.Encodings.Web.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + }, + "runtimeTargets": { + "runtimes/browser/lib/net6.0/System.Text.Encodings.Web.dll": { + "assetType": "runtime", + "rid": "browser" + } + } + }, + "System.Text.Json/8.0.5": { + "type": "package", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0", + "System.Text.Encodings.Web": "8.0.0" + }, + "compile": { + "lib/net6.0/System.Text.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/System.Text.Json.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/System.Text.Json.targets": {} + } + }, + "System.Threading/4.3.0": { + "type": "package", + "dependencies": { + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + }, + "compile": { + "ref/netstandard1.3/_._": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard1.3/System.Threading.dll": {} + } + }, + "System.Threading.Tasks/4.3.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + }, + "compile": { + "ref/netstandard1.3/System.Threading.Tasks.dll": { + "related": ".xml" + } + } + }, + "System.Threading.Thread/4.3.0": { + "type": "package", + "dependencies": { + "System.Runtime": "4.3.0" + }, + "compile": { + "ref/netstandard1.3/_._": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard1.3/System.Threading.Thread.dll": {} + } + }, + "System.Threading.ThreadPool/4.3.0": { + "type": "package", + "dependencies": { + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + }, + "compile": { + "ref/netstandard1.3/_._": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard1.3/System.Threading.ThreadPool.dll": {} + } + }, + "TimeZoneConverter/6.0.1": { + "type": "package", + "compile": { + "lib/net6.0/TimeZoneConverter.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/TimeZoneConverter.dll": { + "related": ".xml" + } + } + }, + "YamlDotNet/13.7.1": { + "type": "package", + "compile": { + "lib/net6.0/YamlDotNet.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/YamlDotNet.dll": { + "related": ".xml" + } + } + } + } + }, + "libraries": { + "AspNetCoreRateLimit/5.0.0": { + "sha512": "6fq9+o1maGADUmpK/PvcF0DtXW2+7bSkIL7MDIo/agbIHKN8XkMQF4oze60DO731WaQmHmK260hB30FwPzCmEg==", + "type": "package", + "path": "aspnetcoreratelimit/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "aspnetcoreratelimit.5.0.0.nupkg.sha512", + "aspnetcoreratelimit.nuspec", + "lib/net6.0/AspNetCoreRateLimit.dll" + ] + }, + "Autofac/8.1.0": { + "sha512": "O2QT+0DSTBR2Ojpacmcj3L0KrnnXTFrwLl/OW1lBUDiHhb89msHEHNhTA8AlK3jdFiAfMbAYyQaJVvRe6oSBcQ==", + "type": "package", + "path": "autofac/8.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "autofac.8.1.0.nupkg.sha512", + "autofac.nuspec", + "icon.png", + "lib/net6.0/Autofac.dll", + "lib/net6.0/Autofac.xml", + "lib/net7.0/Autofac.dll", + "lib/net7.0/Autofac.xml", + "lib/net8.0/Autofac.dll", + "lib/net8.0/Autofac.xml", + "lib/netstandard2.0/Autofac.dll", + "lib/netstandard2.0/Autofac.xml", + "lib/netstandard2.1/Autofac.dll", + "lib/netstandard2.1/Autofac.xml" + ] + }, + "Autofac.Extensions.DependencyInjection/10.0.0": { + "sha512": "ZjR/onUlP7BzQ7VBBigQepWLAyAzi3VRGX3pP6sBqkPRiT61fsTZqbTpRUKxo30TMgbs1o3y6bpLbETix4SJog==", + "type": "package", + "path": "autofac.extensions.dependencyinjection/10.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "autofac.extensions.dependencyinjection.10.0.0.nupkg.sha512", + "autofac.extensions.dependencyinjection.nuspec", + "icon.png", + "lib/net6.0/Autofac.Extensions.DependencyInjection.dll", + "lib/net6.0/Autofac.Extensions.DependencyInjection.xml", + "lib/net7.0/Autofac.Extensions.DependencyInjection.dll", + "lib/net7.0/Autofac.Extensions.DependencyInjection.xml", + "lib/net8.0/Autofac.Extensions.DependencyInjection.dll", + "lib/net8.0/Autofac.Extensions.DependencyInjection.xml", + "lib/netstandard2.0/Autofac.Extensions.DependencyInjection.dll", + "lib/netstandard2.0/Autofac.Extensions.DependencyInjection.xml", + "lib/netstandard2.1/Autofac.Extensions.DependencyInjection.dll", + "lib/netstandard2.1/Autofac.Extensions.DependencyInjection.xml" + ] + }, + "AutoMapper/12.0.1": { + "sha512": "hvV62vl6Hp/WfQ24yzo3Co9+OPl8wH8hApwVtgWpiAynVJkUcs7xvehnSftawL8Pe8FrPffBRM3hwzLQqWDNjA==", + "type": "package", + "path": "automapper/12.0.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "automapper.12.0.1.nupkg.sha512", + "automapper.nuspec", + "icon.png", + "lib/netstandard2.1/AutoMapper.dll", + "lib/netstandard2.1/AutoMapper.xml" + ] + }, + "CircularBuffer/1.4.0": { + "sha512": "BYW7UWlnqsxHKOJeFlgRwXgVhRt2NbebWsNyQ7WsDN4u5jHiaX4om8deUjNvy1Ot9JQq2oTIGLOJ/p8EpGBMxQ==", + "type": "package", + "path": "circularbuffer/1.4.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE/LICENSE", + "circularbuffer.1.4.0.nupkg.sha512", + "circularbuffer.nuspec", + "lib/net461/CircularBuffer.dll", + "lib/net461/CircularBuffer.xml", + "lib/net5.0/CircularBuffer.dll", + "lib/net5.0/CircularBuffer.xml", + "lib/net6.0/CircularBuffer.dll", + "lib/net6.0/CircularBuffer.xml", + "lib/net7.0/CircularBuffer.dll", + "lib/net7.0/CircularBuffer.xml", + "lib/net8.0/CircularBuffer.dll", + "lib/net8.0/CircularBuffer.xml", + "lib/netstandard2.0/CircularBuffer.dll", + "lib/netstandard2.0/CircularBuffer.xml", + "logo.png" + ] + }, + "Dapper/2.1.35": { + "sha512": "YKRwjVfrG7GYOovlGyQoMvr1/IJdn+7QzNXJxyMh0YfFF5yvDmTYaJOVYWsckreNjGsGSEtrMTpnzxTUq/tZQw==", + "type": "package", + "path": "dapper/2.1.35", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Dapper.png", + "dapper.2.1.35.nupkg.sha512", + "dapper.nuspec", + "lib/net461/Dapper.dll", + "lib/net461/Dapper.xml", + "lib/net5.0/Dapper.dll", + "lib/net5.0/Dapper.xml", + "lib/net7.0/Dapper.dll", + "lib/net7.0/Dapper.xml", + "lib/netstandard2.0/Dapper.dll", + "lib/netstandard2.0/Dapper.xml", + "readme.md" + ] + }, + "FluentValidation/11.10.0": { + "sha512": "qsJGSJDdZ8qiG+lVJ70PZfJHcEdq8UQZ/tZDXoj78/iHKG6lVKtMJsD11zyyv/IPc7rwqGqnFoFLTNzpo3IPYg==", + "type": "package", + "path": "fluentvalidation/11.10.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "fluent-validation-icon.png", + "fluentvalidation.11.10.0.nupkg.sha512", + "fluentvalidation.nuspec", + "lib/net5.0/FluentValidation.dll", + "lib/net5.0/FluentValidation.xml", + "lib/net6.0/FluentValidation.dll", + "lib/net6.0/FluentValidation.xml", + "lib/net7.0/FluentValidation.dll", + "lib/net7.0/FluentValidation.xml", + "lib/net8.0/FluentValidation.dll", + "lib/net8.0/FluentValidation.xml", + "lib/netstandard2.0/FluentValidation.dll", + "lib/netstandard2.0/FluentValidation.xml", + "lib/netstandard2.1/FluentValidation.dll", + "lib/netstandard2.1/FluentValidation.xml" + ] + }, + "FluentValidation.AspNetCore/11.3.0": { + "sha512": "jtFVgKnDFySyBlPS8bZbTKEEwJZnn11rXXJ2SQnjDhZ56rQqybBg9Joq4crRLz3y0QR8WoOq4iE4piV81w/Djg==", + "type": "package", + "path": "fluentvalidation.aspnetcore/11.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "fluent-validation-icon.png", + "fluentvalidation.aspnetcore.11.3.0.nupkg.sha512", + "fluentvalidation.aspnetcore.nuspec", + "lib/net5.0/FluentValidation.AspNetCore.dll", + "lib/net5.0/FluentValidation.AspNetCore.xml", + "lib/net6.0/FluentValidation.AspNetCore.dll", + "lib/net6.0/FluentValidation.AspNetCore.xml", + "lib/netcoreapp3.1/FluentValidation.AspNetCore.dll", + "lib/netcoreapp3.1/FluentValidation.AspNetCore.xml" + ] + }, + "FluentValidation.DependencyInjectionExtensions/11.10.0": { + "sha512": "hIe+i6P+ZUxFh6lJOBXRs4EGE/thcub0Lpdk2FF2/JBKJUqDqE2xDnBIiqTMkpXLoekgBN0SlhJT0vpeNr1J6g==", + "type": "package", + "path": "fluentvalidation.dependencyinjectionextensions/11.10.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "fluent-validation-icon.png", + "fluentvalidation.dependencyinjectionextensions.11.10.0.nupkg.sha512", + "fluentvalidation.dependencyinjectionextensions.nuspec", + "lib/netstandard2.0/FluentValidation.DependencyInjectionExtensions.dll", + "lib/netstandard2.0/FluentValidation.DependencyInjectionExtensions.xml", + "lib/netstandard2.1/FluentValidation.DependencyInjectionExtensions.dll", + "lib/netstandard2.1/FluentValidation.DependencyInjectionExtensions.xml" + ] + }, + "Fluid.Core/2.5.0": { + "sha512": "XrCupimfbdYIWpW64j3irIPRpV0UOBgUOiZTXAq00YhSzq/LAMG2fzVIXbUo6Xxfl3ywTY48yF4A9Lj2jABj5w==", + "type": "package", + "path": "fluid.core/2.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "fluid.core.2.5.0.nupkg.sha512", + "fluid.core.nuspec", + "lib/net5.0/Fluid.dll", + "lib/net5.0/Fluid.pdb", + "lib/net5.0/Fluid.xml", + "lib/net6.0/Fluid.dll", + "lib/net6.0/Fluid.pdb", + "lib/net6.0/Fluid.xml", + "lib/net7.0/Fluid.dll", + "lib/net7.0/Fluid.pdb", + "lib/net7.0/Fluid.xml", + "lib/netcoreapp3.1/Fluid.dll", + "lib/netcoreapp3.1/Fluid.pdb", + "lib/netcoreapp3.1/Fluid.xml", + "lib/netstandard2.0/Fluid.dll", + "lib/netstandard2.0/Fluid.pdb", + "lib/netstandard2.0/Fluid.xml", + "lib/netstandard2.1/Fluid.dll", + "lib/netstandard2.1/Fluid.pdb", + "lib/netstandard2.1/Fluid.xml", + "logo_64x64.png" + ] + }, + "GitVersion.MsBuild/5.12.0": { + "sha512": "dJuigXycpJNOiLT9or7mkHSkGFHgGW3/p6cNNYEKZBa7Hhp1FdX/cvqYWWYhRLpfoZOedeA7aRbYiOB3vW/dvA==", + "type": "package", + "path": "gitversion.msbuild/5.12.0", + "hasTools": true, + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "build/GitVersion.MsBuild.props", + "build/GitVersion.MsBuild.targets", + "buildMultiTargeting/GitVersion.MsBuild.props", + "buildMultiTargeting/GitVersion.MsBuild.targets", + "gitversion.msbuild.5.12.0.nupkg.sha512", + "gitversion.msbuild.nuspec", + "package_icon.png", + "tools/GitVersion.MsBuild.props", + "tools/GitVersion.MsBuild.targets", + "tools/net48/GitVersion.Core.dll", + "tools/net48/GitVersion.LibGit2Sharp.dll", + "tools/net48/GitVersion.MsBuild.deps.json", + "tools/net48/GitVersion.MsBuild.dll", + "tools/net48/JetBrains.Annotations.dll", + "tools/net48/LibGit2Sharp.dll", + "tools/net48/LibGit2Sharp.dll.config", + "tools/net48/Microsoft.Bcl.AsyncInterfaces.dll", + "tools/net48/Microsoft.Extensions.Configuration.Abstractions.dll", + "tools/net48/Microsoft.Extensions.Configuration.Binder.dll", + "tools/net48/Microsoft.Extensions.Configuration.CommandLine.dll", + "tools/net48/Microsoft.Extensions.Configuration.EnvironmentVariables.dll", + "tools/net48/Microsoft.Extensions.Configuration.FileExtensions.dll", + "tools/net48/Microsoft.Extensions.Configuration.Json.dll", + "tools/net48/Microsoft.Extensions.Configuration.UserSecrets.dll", + "tools/net48/Microsoft.Extensions.Configuration.dll", + "tools/net48/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "tools/net48/Microsoft.Extensions.DependencyInjection.dll", + "tools/net48/Microsoft.Extensions.FileProviders.Abstractions.dll", + "tools/net48/Microsoft.Extensions.FileProviders.Physical.dll", + "tools/net48/Microsoft.Extensions.FileSystemGlobbing.dll", + "tools/net48/Microsoft.Extensions.Hosting.Abstractions.dll", + "tools/net48/Microsoft.Extensions.Hosting.dll", + "tools/net48/Microsoft.Extensions.Logging.Abstractions.dll", + "tools/net48/Microsoft.Extensions.Logging.Configuration.dll", + "tools/net48/Microsoft.Extensions.Logging.Console.dll", + "tools/net48/Microsoft.Extensions.Logging.Debug.dll", + "tools/net48/Microsoft.Extensions.Logging.EventLog.dll", + "tools/net48/Microsoft.Extensions.Logging.EventSource.dll", + "tools/net48/Microsoft.Extensions.Logging.dll", + "tools/net48/Microsoft.Extensions.Options.ConfigurationExtensions.dll", + "tools/net48/Microsoft.Extensions.Options.dll", + "tools/net48/Microsoft.Extensions.Primitives.dll", + "tools/net48/Polly.dll", + "tools/net48/System.Buffers.dll", + "tools/net48/System.Diagnostics.DiagnosticSource.dll", + "tools/net48/System.Memory.dll", + "tools/net48/System.Numerics.Vectors.dll", + "tools/net48/System.Runtime.CompilerServices.Unsafe.dll", + "tools/net48/System.Text.Encodings.Web.dll", + "tools/net48/System.Text.Json.dll", + "tools/net48/System.Threading.Tasks.Extensions.dll", + "tools/net48/System.ValueTuple.dll", + "tools/net48/YamlDotNet.dll", + "tools/net48/gitversion.exe", + "tools/net48/gitversion.exe.config", + "tools/net48/lib/linux-arm/libgit2-b7bad55.so", + "tools/net48/lib/linux-arm64/libgit2-b7bad55.so", + "tools/net48/lib/linux-musl-arm/libgit2-b7bad55.so", + "tools/net48/lib/linux-musl-arm64/libgit2-b7bad55.so", + "tools/net48/lib/linux-musl-x64/libgit2-b7bad55.so", + "tools/net48/lib/linux-x64/libgit2-b7bad55.so", + "tools/net48/lib/osx-arm64/libgit2-b7bad55.dylib", + "tools/net48/lib/osx-x64/libgit2-b7bad55.dylib", + "tools/net48/lib/win32/arm64/git2-b7bad55.dll", + "tools/net48/lib/win32/x64/git2-b7bad55.dll", + "tools/net48/lib/win32/x86/git2-b7bad55.dll", + "tools/net5.0/GitVersion.Core.dll", + "tools/net5.0/GitVersion.LibGit2Sharp.dll", + "tools/net5.0/GitVersion.MsBuild.deps.json", + "tools/net5.0/GitVersion.MsBuild.dll", + "tools/net5.0/LibGit2Sharp.dll", + "tools/net5.0/Microsoft.Extensions.Configuration.Abstractions.dll", + "tools/net5.0/Microsoft.Extensions.Configuration.Binder.dll", + "tools/net5.0/Microsoft.Extensions.Configuration.CommandLine.dll", + "tools/net5.0/Microsoft.Extensions.Configuration.EnvironmentVariables.dll", + "tools/net5.0/Microsoft.Extensions.Configuration.FileExtensions.dll", + "tools/net5.0/Microsoft.Extensions.Configuration.Json.dll", + "tools/net5.0/Microsoft.Extensions.Configuration.UserSecrets.dll", + "tools/net5.0/Microsoft.Extensions.Configuration.dll", + "tools/net5.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "tools/net5.0/Microsoft.Extensions.DependencyInjection.dll", + "tools/net5.0/Microsoft.Extensions.FileProviders.Abstractions.dll", + "tools/net5.0/Microsoft.Extensions.FileProviders.Physical.dll", + "tools/net5.0/Microsoft.Extensions.FileSystemGlobbing.dll", + "tools/net5.0/Microsoft.Extensions.Hosting.Abstractions.dll", + "tools/net5.0/Microsoft.Extensions.Hosting.dll", + "tools/net5.0/Microsoft.Extensions.Logging.Abstractions.dll", + "tools/net5.0/Microsoft.Extensions.Logging.Configuration.dll", + "tools/net5.0/Microsoft.Extensions.Logging.Console.dll", + "tools/net5.0/Microsoft.Extensions.Logging.Debug.dll", + "tools/net5.0/Microsoft.Extensions.Logging.EventLog.dll", + "tools/net5.0/Microsoft.Extensions.Logging.EventSource.dll", + "tools/net5.0/Microsoft.Extensions.Logging.dll", + "tools/net5.0/Microsoft.Extensions.Options.ConfigurationExtensions.dll", + "tools/net5.0/Microsoft.Extensions.Options.dll", + "tools/net5.0/Microsoft.Extensions.Primitives.dll", + "tools/net5.0/Polly.dll", + "tools/net5.0/System.Diagnostics.DiagnosticSource.dll", + "tools/net5.0/System.Diagnostics.EventLog.dll", + "tools/net5.0/System.Runtime.CompilerServices.Unsafe.dll", + "tools/net5.0/System.Text.Encodings.Web.dll", + "tools/net5.0/System.Text.Json.dll", + "tools/net5.0/YamlDotNet.dll", + "tools/net5.0/gitversion.deps.json", + "tools/net5.0/gitversion.dll", + "tools/net5.0/gitversion.exe", + "tools/net5.0/gitversion.runtimeconfig.json", + "tools/net5.0/runtimes/linux-arm/native/libgit2-b7bad55.so", + "tools/net5.0/runtimes/linux-arm64/native/libgit2-b7bad55.so", + "tools/net5.0/runtimes/linux-musl-arm/native/libgit2-b7bad55.so", + "tools/net5.0/runtimes/linux-musl-arm64/native/libgit2-b7bad55.so", + "tools/net5.0/runtimes/linux-musl-x64/native/libgit2-b7bad55.so", + "tools/net5.0/runtimes/linux-x64/native/libgit2-b7bad55.so", + "tools/net5.0/runtimes/osx-arm64/native/libgit2-b7bad55.dylib", + "tools/net5.0/runtimes/osx-x64/native/libgit2-b7bad55.dylib", + "tools/net5.0/runtimes/win-arm64/native/git2-b7bad55.dll", + "tools/net5.0/runtimes/win-x64/native/git2-b7bad55.dll", + "tools/net5.0/runtimes/win-x86/native/git2-b7bad55.dll", + "tools/net5.0/runtimes/win/lib/netcoreapp3.1/System.Diagnostics.EventLog.Messages.dll", + "tools/net5.0/runtimes/win/lib/netcoreapp3.1/System.Diagnostics.EventLog.dll", + "tools/net6.0/GitVersion.Core.dll", + "tools/net6.0/GitVersion.LibGit2Sharp.dll", + "tools/net6.0/GitVersion.MsBuild.deps.json", + "tools/net6.0/GitVersion.MsBuild.dll", + "tools/net6.0/LibGit2Sharp.dll", + "tools/net6.0/Microsoft.Extensions.Configuration.Abstractions.dll", + "tools/net6.0/Microsoft.Extensions.Configuration.Binder.dll", + "tools/net6.0/Microsoft.Extensions.Configuration.CommandLine.dll", + "tools/net6.0/Microsoft.Extensions.Configuration.EnvironmentVariables.dll", + "tools/net6.0/Microsoft.Extensions.Configuration.FileExtensions.dll", + "tools/net6.0/Microsoft.Extensions.Configuration.Json.dll", + "tools/net6.0/Microsoft.Extensions.Configuration.UserSecrets.dll", + "tools/net6.0/Microsoft.Extensions.Configuration.dll", + "tools/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "tools/net6.0/Microsoft.Extensions.DependencyInjection.dll", + "tools/net6.0/Microsoft.Extensions.FileProviders.Abstractions.dll", + "tools/net6.0/Microsoft.Extensions.FileProviders.Physical.dll", + "tools/net6.0/Microsoft.Extensions.FileSystemGlobbing.dll", + "tools/net6.0/Microsoft.Extensions.Hosting.Abstractions.dll", + "tools/net6.0/Microsoft.Extensions.Hosting.dll", + "tools/net6.0/Microsoft.Extensions.Logging.Abstractions.dll", + "tools/net6.0/Microsoft.Extensions.Logging.Configuration.dll", + "tools/net6.0/Microsoft.Extensions.Logging.Console.dll", + "tools/net6.0/Microsoft.Extensions.Logging.Debug.dll", + "tools/net6.0/Microsoft.Extensions.Logging.EventLog.dll", + "tools/net6.0/Microsoft.Extensions.Logging.EventSource.dll", + "tools/net6.0/Microsoft.Extensions.Logging.dll", + "tools/net6.0/Microsoft.Extensions.Options.ConfigurationExtensions.dll", + "tools/net6.0/Microsoft.Extensions.Options.dll", + "tools/net6.0/Microsoft.Extensions.Primitives.dll", + "tools/net6.0/Polly.dll", + "tools/net6.0/System.Diagnostics.EventLog.dll", + "tools/net6.0/YamlDotNet.dll", + "tools/net6.0/gitversion.deps.json", + "tools/net6.0/gitversion.dll", + "tools/net6.0/gitversion.exe", + "tools/net6.0/gitversion.runtimeconfig.json", + "tools/net6.0/runtimes/linux-arm/native/libgit2-b7bad55.so", + "tools/net6.0/runtimes/linux-arm64/native/libgit2-b7bad55.so", + "tools/net6.0/runtimes/linux-musl-arm/native/libgit2-b7bad55.so", + "tools/net6.0/runtimes/linux-musl-arm64/native/libgit2-b7bad55.so", + "tools/net6.0/runtimes/linux-musl-x64/native/libgit2-b7bad55.so", + "tools/net6.0/runtimes/linux-x64/native/libgit2-b7bad55.so", + "tools/net6.0/runtimes/osx-arm64/native/libgit2-b7bad55.dylib", + "tools/net6.0/runtimes/osx-x64/native/libgit2-b7bad55.dylib", + "tools/net6.0/runtimes/win-arm64/native/git2-b7bad55.dll", + "tools/net6.0/runtimes/win-x64/native/git2-b7bad55.dll", + "tools/net6.0/runtimes/win-x86/native/git2-b7bad55.dll", + "tools/net6.0/runtimes/win/lib/net6.0/System.Diagnostics.EventLog.Messages.dll", + "tools/net6.0/runtimes/win/lib/net6.0/System.Diagnostics.EventLog.dll", + "tools/netcoreapp3.1/GitVersion.Core.dll", + "tools/netcoreapp3.1/GitVersion.LibGit2Sharp.dll", + "tools/netcoreapp3.1/GitVersion.MsBuild.deps.json", + "tools/netcoreapp3.1/GitVersion.MsBuild.dll", + "tools/netcoreapp3.1/LibGit2Sharp.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Configuration.Abstractions.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Configuration.Binder.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Configuration.CommandLine.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Configuration.EnvironmentVariables.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Configuration.FileExtensions.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Configuration.Json.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Configuration.UserSecrets.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Configuration.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.DependencyInjection.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.FileProviders.Abstractions.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.FileProviders.Physical.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.FileSystemGlobbing.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Hosting.Abstractions.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Hosting.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Logging.Abstractions.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Logging.Configuration.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Logging.Console.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Logging.Debug.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Logging.EventLog.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Logging.EventSource.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Logging.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Options.ConfigurationExtensions.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Options.dll", + "tools/netcoreapp3.1/Microsoft.Extensions.Primitives.dll", + "tools/netcoreapp3.1/Microsoft.Win32.Registry.dll", + "tools/netcoreapp3.1/Polly.dll", + "tools/netcoreapp3.1/System.Diagnostics.DiagnosticSource.dll", + "tools/netcoreapp3.1/System.Diagnostics.EventLog.dll", + "tools/netcoreapp3.1/System.Runtime.CompilerServices.Unsafe.dll", + "tools/netcoreapp3.1/System.Security.AccessControl.dll", + "tools/netcoreapp3.1/System.Security.Principal.Windows.dll", + "tools/netcoreapp3.1/System.Text.Encodings.Web.dll", + "tools/netcoreapp3.1/System.Text.Json.dll", + "tools/netcoreapp3.1/YamlDotNet.dll", + "tools/netcoreapp3.1/gitversion.deps.json", + "tools/netcoreapp3.1/gitversion.dll", + "tools/netcoreapp3.1/gitversion.exe", + "tools/netcoreapp3.1/gitversion.runtimeconfig.json", + "tools/netcoreapp3.1/runtimes/linux-arm/native/libgit2-b7bad55.so", + "tools/netcoreapp3.1/runtimes/linux-arm64/native/libgit2-b7bad55.so", + "tools/netcoreapp3.1/runtimes/linux-musl-arm/native/libgit2-b7bad55.so", + "tools/netcoreapp3.1/runtimes/linux-musl-arm64/native/libgit2-b7bad55.so", + "tools/netcoreapp3.1/runtimes/linux-musl-x64/native/libgit2-b7bad55.so", + "tools/netcoreapp3.1/runtimes/linux-x64/native/libgit2-b7bad55.so", + "tools/netcoreapp3.1/runtimes/osx-arm64/native/libgit2-b7bad55.dylib", + "tools/netcoreapp3.1/runtimes/osx-x64/native/libgit2-b7bad55.dylib", + "tools/netcoreapp3.1/runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "tools/netcoreapp3.1/runtimes/win-arm64/native/git2-b7bad55.dll", + "tools/netcoreapp3.1/runtimes/win-x64/native/git2-b7bad55.dll", + "tools/netcoreapp3.1/runtimes/win-x86/native/git2-b7bad55.dll", + "tools/netcoreapp3.1/runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll", + "tools/netcoreapp3.1/runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "tools/netcoreapp3.1/runtimes/win/lib/netcoreapp3.1/System.Diagnostics.EventLog.Messages.dll", + "tools/netcoreapp3.1/runtimes/win/lib/netcoreapp3.1/System.Diagnostics.EventLog.dll", + "tools/netcoreapp3.1/runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll" + ] + }, + "Google.Protobuf/3.26.1": { + "sha512": "CHZX8zXqhF/fdUtd+AYzew8T2HFkAoe5c7lbGxZY/qryAlQXckDvM5BfOJjXlMS7kyICqQTMszj4w1bX5uBJ/w==", + "type": "package", + "path": "google.protobuf/3.26.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "google.protobuf.3.26.1.nupkg.sha512", + "google.protobuf.nuspec", + "lib/net45/Google.Protobuf.dll", + "lib/net45/Google.Protobuf.pdb", + "lib/net45/Google.Protobuf.xml", + "lib/net5.0/Google.Protobuf.dll", + "lib/net5.0/Google.Protobuf.pdb", + "lib/net5.0/Google.Protobuf.xml", + "lib/netstandard1.1/Google.Protobuf.dll", + "lib/netstandard1.1/Google.Protobuf.pdb", + "lib/netstandard1.1/Google.Protobuf.xml", + "lib/netstandard2.0/Google.Protobuf.dll", + "lib/netstandard2.0/Google.Protobuf.pdb", + "lib/netstandard2.0/Google.Protobuf.xml" + ] + }, + "Grpc.AspNetCore/2.57.0": { + "sha512": "mTKo9d5DYOxTFhg/8sdX5O3+gw1uFESmu7WhH04t5PSPltpQ10ZiK+Mr/ju/TW3MwxJg8uHt71fWL6AS443izw==", + "type": "package", + "path": "grpc.aspnetcore/2.57.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "grpc.aspnetcore.2.57.0.nupkg.sha512", + "grpc.aspnetcore.nuspec", + "lib/net6.0/_._", + "lib/net7.0/_._", + "lib/net8.0/_._", + "packageIcon.png" + ] + }, + "Grpc.AspNetCore.Server/2.57.0": { + "sha512": "g4JKqJ3RB7WKOrBxMSCkRc/1Xa5GqYlVb7k8OjUsERKW7LdSQ0ajcFMZ4Q79BZgA/xbJlGttmq4ewyzpBqGetA==", + "type": "package", + "path": "grpc.aspnetcore.server/2.57.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "grpc.aspnetcore.server.2.57.0.nupkg.sha512", + "grpc.aspnetcore.server.nuspec", + "lib/net6.0/Grpc.AspNetCore.Server.dll", + "lib/net6.0/Grpc.AspNetCore.Server.pdb", + "lib/net6.0/Grpc.AspNetCore.Server.xml", + "lib/net7.0/Grpc.AspNetCore.Server.dll", + "lib/net7.0/Grpc.AspNetCore.Server.pdb", + "lib/net7.0/Grpc.AspNetCore.Server.xml", + "lib/net8.0/Grpc.AspNetCore.Server.dll", + "lib/net8.0/Grpc.AspNetCore.Server.pdb", + "lib/net8.0/Grpc.AspNetCore.Server.xml", + "packageIcon.png" + ] + }, + "Grpc.AspNetCore.Server.ClientFactory/2.57.0": { + "sha512": "Ucl50YKMMRaP/ikx20v6tDGdNaRzeiujmw8kmAFy3/4f8+d1mDY8wn3vcXpIflX4IE+WvZQOTHz5r/3/GutbQw==", + "type": "package", + "path": "grpc.aspnetcore.server.clientfactory/2.57.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "grpc.aspnetcore.server.clientfactory.2.57.0.nupkg.sha512", + "grpc.aspnetcore.server.clientfactory.nuspec", + "lib/net6.0/Grpc.AspNetCore.Server.ClientFactory.dll", + "lib/net6.0/Grpc.AspNetCore.Server.ClientFactory.pdb", + "lib/net6.0/Grpc.AspNetCore.Server.ClientFactory.xml", + "lib/net7.0/Grpc.AspNetCore.Server.ClientFactory.dll", + "lib/net7.0/Grpc.AspNetCore.Server.ClientFactory.pdb", + "lib/net7.0/Grpc.AspNetCore.Server.ClientFactory.xml", + "lib/net8.0/Grpc.AspNetCore.Server.ClientFactory.dll", + "lib/net8.0/Grpc.AspNetCore.Server.ClientFactory.pdb", + "lib/net8.0/Grpc.AspNetCore.Server.ClientFactory.xml", + "packageIcon.png" + ] + }, + "Grpc.Core.Api/2.62.0": { + "sha512": "q4Jj6bRZHNnE4CMLqgjiBUCKLit+tRr0simZsS2W6U++akd7CzXByeKy2tddqT68hFzP2XzceXA2YtBTfWtixA==", + "type": "package", + "path": "grpc.core.api/2.62.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "grpc.core.api.2.62.0.nupkg.sha512", + "grpc.core.api.nuspec", + "lib/net462/Grpc.Core.Api.dll", + "lib/net462/Grpc.Core.Api.pdb", + "lib/net462/Grpc.Core.Api.xml", + "lib/netstandard2.0/Grpc.Core.Api.dll", + "lib/netstandard2.0/Grpc.Core.Api.pdb", + "lib/netstandard2.0/Grpc.Core.Api.xml", + "lib/netstandard2.1/Grpc.Core.Api.dll", + "lib/netstandard2.1/Grpc.Core.Api.pdb", + "lib/netstandard2.1/Grpc.Core.Api.xml", + "packageIcon.png" + ] + }, + "Grpc.Net.Client/2.62.0": { + "sha512": "C7HxLt+wWPTpPFORRHkxxtDLL+K/jXSmZBaPLhFM8AEkN0bYjklIfCwnzajn1gcbRcEETBb0WnRgHJdVzpwbCg==", + "type": "package", + "path": "grpc.net.client/2.62.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "grpc.net.client.2.62.0.nupkg.sha512", + "grpc.net.client.nuspec", + "lib/net462/Grpc.Net.Client.dll", + "lib/net462/Grpc.Net.Client.pdb", + "lib/net462/Grpc.Net.Client.xml", + "lib/net6.0/Grpc.Net.Client.dll", + "lib/net6.0/Grpc.Net.Client.pdb", + "lib/net6.0/Grpc.Net.Client.xml", + "lib/net7.0/Grpc.Net.Client.dll", + "lib/net7.0/Grpc.Net.Client.pdb", + "lib/net7.0/Grpc.Net.Client.xml", + "lib/net8.0/Grpc.Net.Client.dll", + "lib/net8.0/Grpc.Net.Client.pdb", + "lib/net8.0/Grpc.Net.Client.xml", + "lib/netstandard2.0/Grpc.Net.Client.dll", + "lib/netstandard2.0/Grpc.Net.Client.pdb", + "lib/netstandard2.0/Grpc.Net.Client.xml", + "lib/netstandard2.1/Grpc.Net.Client.dll", + "lib/netstandard2.1/Grpc.Net.Client.pdb", + "lib/netstandard2.1/Grpc.Net.Client.xml", + "packageIcon.png" + ] + }, + "Grpc.Net.ClientFactory/2.57.0": { + "sha512": "t3+mz7z6e3tezZbekioGOqix4QcOAWRACQqP3v/FA6HxkgraTRceaREPaFTxSFvGrpPtOSkJ3y1WRx0MA+8v9g==", + "type": "package", + "path": "grpc.net.clientfactory/2.57.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "grpc.net.clientfactory.2.57.0.nupkg.sha512", + "grpc.net.clientfactory.nuspec", + "lib/net6.0/Grpc.Net.ClientFactory.dll", + "lib/net6.0/Grpc.Net.ClientFactory.pdb", + "lib/net6.0/Grpc.Net.ClientFactory.xml", + "lib/net7.0/Grpc.Net.ClientFactory.dll", + "lib/net7.0/Grpc.Net.ClientFactory.pdb", + "lib/net7.0/Grpc.Net.ClientFactory.xml", + "lib/net8.0/Grpc.Net.ClientFactory.dll", + "lib/net8.0/Grpc.Net.ClientFactory.pdb", + "lib/net8.0/Grpc.Net.ClientFactory.xml", + "lib/netstandard2.0/Grpc.Net.ClientFactory.dll", + "lib/netstandard2.0/Grpc.Net.ClientFactory.pdb", + "lib/netstandard2.0/Grpc.Net.ClientFactory.xml", + "lib/netstandard2.1/Grpc.Net.ClientFactory.dll", + "lib/netstandard2.1/Grpc.Net.ClientFactory.pdb", + "lib/netstandard2.1/Grpc.Net.ClientFactory.xml", + "packageIcon.png" + ] + }, + "Grpc.Net.Common/2.62.0": { + "sha512": "eBv5I4RPWfdezGXqooU5hs3+XcfVMLk5XDlA4G/Nd9TMX78ZGrFl/lM1Ad187zgBLmH7WPAgfjKRWLBwaa1Wbw==", + "type": "package", + "path": "grpc.net.common/2.62.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "grpc.net.common.2.62.0.nupkg.sha512", + "grpc.net.common.nuspec", + "lib/net6.0/Grpc.Net.Common.dll", + "lib/net6.0/Grpc.Net.Common.pdb", + "lib/net6.0/Grpc.Net.Common.xml", + "lib/net7.0/Grpc.Net.Common.dll", + "lib/net7.0/Grpc.Net.Common.pdb", + "lib/net7.0/Grpc.Net.Common.xml", + "lib/net8.0/Grpc.Net.Common.dll", + "lib/net8.0/Grpc.Net.Common.pdb", + "lib/net8.0/Grpc.Net.Common.xml", + "lib/netstandard2.0/Grpc.Net.Common.dll", + "lib/netstandard2.0/Grpc.Net.Common.pdb", + "lib/netstandard2.0/Grpc.Net.Common.xml", + "lib/netstandard2.1/Grpc.Net.Common.dll", + "lib/netstandard2.1/Grpc.Net.Common.pdb", + "lib/netstandard2.1/Grpc.Net.Common.xml", + "packageIcon.png" + ] + }, + "Grpc.Tools/2.62.0": { + "sha512": "tVU0hseOI3tYI9Z62++01EAUBNsKMQfZfeuZyW9Qa3z1D7IqtQKoU2u+3426uIPCTzVVi8qBgsszThyKam9NQA==", + "type": "package", + "path": "grpc.tools/2.62.0", + "hasTools": true, + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "build/Grpc.Tools.props", + "build/Grpc.Tools.targets", + "build/_grpc/Grpc.CSharp.xml", + "build/_grpc/_Grpc.Tools.props", + "build/_grpc/_Grpc.Tools.targets", + "build/_protobuf/Google.Protobuf.Tools.props", + "build/_protobuf/Google.Protobuf.Tools.targets", + "build/_protobuf/Protobuf.CSharp.xml", + "build/_protobuf/net45/Protobuf.MSBuild.dll", + "build/_protobuf/net45/Protobuf.MSBuild.pdb", + "build/_protobuf/netstandard1.3/Protobuf.MSBuild.dll", + "build/_protobuf/netstandard1.3/Protobuf.MSBuild.pdb", + "build/native/include/google/protobuf/any.proto", + "build/native/include/google/protobuf/api.proto", + "build/native/include/google/protobuf/descriptor.proto", + "build/native/include/google/protobuf/duration.proto", + "build/native/include/google/protobuf/empty.proto", + "build/native/include/google/protobuf/field_mask.proto", + "build/native/include/google/protobuf/source_context.proto", + "build/native/include/google/protobuf/struct.proto", + "build/native/include/google/protobuf/timestamp.proto", + "build/native/include/google/protobuf/type.proto", + "build/native/include/google/protobuf/wrappers.proto", + "grpc.tools.2.62.0.nupkg.sha512", + "grpc.tools.nuspec", + "packageIcon.png", + "tools/linux_arm64/grpc_csharp_plugin", + "tools/linux_arm64/protoc", + "tools/linux_x64/grpc_csharp_plugin", + "tools/linux_x64/protoc", + "tools/linux_x86/grpc_csharp_plugin", + "tools/linux_x86/protoc", + "tools/macosx_x64/grpc_csharp_plugin", + "tools/macosx_x64/protoc", + "tools/windows_x64/grpc_csharp_plugin.exe", + "tools/windows_x64/protoc.exe", + "tools/windows_x86/grpc_csharp_plugin.exe", + "tools/windows_x86/protoc.exe" + ] + }, + "JetBrains.Annotations/2024.3.0": { + "sha512": "ox5pkeLQXjvJdyAB4b2sBYAlqZGLh3PjSnP1bQNVx72ONuTJ9+34/+Rq91Fc0dG29XG9RgZur9+NcP4riihTug==", + "type": "package", + "path": "jetbrains.annotations/2024.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "icon.png", + "jetbrains.annotations.2024.3.0.nupkg.sha512", + "jetbrains.annotations.nuspec", + "lib/net20/JetBrains.Annotations.dll", + "lib/net20/JetBrains.Annotations.xml", + "lib/netstandard1.0/JetBrains.Annotations.deps.json", + "lib/netstandard1.0/JetBrains.Annotations.dll", + "lib/netstandard1.0/JetBrains.Annotations.xml", + "lib/netstandard2.0/JetBrains.Annotations.deps.json", + "lib/netstandard2.0/JetBrains.Annotations.dll", + "lib/netstandard2.0/JetBrains.Annotations.xml", + "lib/portable40-net40+sl5+win8+wp8+wpa81/JetBrains.Annotations.dll", + "lib/portable40-net40+sl5+win8+wp8+wpa81/JetBrains.Annotations.xml", + "readme.md" + ] + }, + "MailKit/3.5.0": { + "sha512": "7tvc+Um6JWOgvAv4I7DhPEDbHVaRH06m1ECZoJw2n9cyBcCZbyZy4AhVhTxGjM/vFYogh+UDboOnn7xd7WRV1Q==", + "type": "package", + "path": "mailkit/3.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "icons/mailkit-50.png", + "lib/net462/MailKit.dll", + "lib/net462/MailKit.pdb", + "lib/net462/MailKit.xml", + "lib/net47/MailKit.dll", + "lib/net47/MailKit.pdb", + "lib/net47/MailKit.xml", + "lib/net48/MailKit.dll", + "lib/net48/MailKit.pdb", + "lib/net48/MailKit.xml", + "lib/net6.0/MailKit.dll", + "lib/net6.0/MailKit.pdb", + "lib/net6.0/MailKit.xml", + "lib/netstandard2.0/MailKit.dll", + "lib/netstandard2.0/MailKit.pdb", + "lib/netstandard2.0/MailKit.xml", + "lib/netstandard2.1/MailKit.dll", + "lib/netstandard2.1/MailKit.pdb", + "lib/netstandard2.1/MailKit.xml", + "mailkit.3.5.0.nupkg.sha512", + "mailkit.nuspec" + ] + }, + "McMaster.Extensions.CommandLineUtils/4.0.2": { + "sha512": "/M/p9fPUfu1dtIa+/xJS3hdp4aNIVr3c0reLFP4ZKo1vZy1sXeWeyaSapoVk8dmT79OxJTpLUGDdv0ReBd8d8A==", + "type": "package", + "path": "mcmaster.extensions.commandlineutils/4.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "icon.png", + "lib/net45/McMaster.Extensions.CommandLineUtils.dll", + "lib/net45/McMaster.Extensions.CommandLineUtils.xml", + "lib/netstandard2.0/McMaster.Extensions.CommandLineUtils.dll", + "lib/netstandard2.0/McMaster.Extensions.CommandLineUtils.xml", + "lib/netstandard2.1/McMaster.Extensions.CommandLineUtils.dll", + "lib/netstandard2.1/McMaster.Extensions.CommandLineUtils.xml", + "mcmaster.extensions.commandlineutils.4.0.2.nupkg.sha512", + "mcmaster.extensions.commandlineutils.nuspec" + ] + }, + "Microsoft.Bcl.AsyncInterfaces/6.0.0": { + "sha512": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==", + "type": "package", + "path": "microsoft.bcl.asyncinterfaces/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/Microsoft.Bcl.AsyncInterfaces.dll", + "lib/net461/Microsoft.Bcl.AsyncInterfaces.xml", + "lib/netstandard2.0/Microsoft.Bcl.AsyncInterfaces.dll", + "lib/netstandard2.0/Microsoft.Bcl.AsyncInterfaces.xml", + "lib/netstandard2.1/Microsoft.Bcl.AsyncInterfaces.dll", + "lib/netstandard2.1/Microsoft.Bcl.AsyncInterfaces.xml", + "microsoft.bcl.asyncinterfaces.6.0.0.nupkg.sha512", + "microsoft.bcl.asyncinterfaces.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Bcl.TimeProvider/8.0.0": { + "sha512": "f5Kr5JepAbiGo7uDmhgvMqhntwxqXNn6/IpTBSSI4cuHhgnJGrLxFRhMjVpRkLPp6zJXO0/G0l3j9p9zSJxa+w==", + "type": "package", + "path": "microsoft.bcl.timeprovider/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Bcl.TimeProvider.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Bcl.TimeProvider.targets", + "lib/net462/Microsoft.Bcl.TimeProvider.dll", + "lib/net462/Microsoft.Bcl.TimeProvider.xml", + "lib/net8.0/Microsoft.Bcl.TimeProvider.dll", + "lib/net8.0/Microsoft.Bcl.TimeProvider.xml", + "lib/netstandard2.0/Microsoft.Bcl.TimeProvider.dll", + "lib/netstandard2.0/Microsoft.Bcl.TimeProvider.xml", + "microsoft.bcl.timeprovider.8.0.0.nupkg.sha512", + "microsoft.bcl.timeprovider.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.CSharp/4.7.0": { + "sha512": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==", + "type": "package", + "path": "microsoft.csharp/4.7.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/netcore50/Microsoft.CSharp.dll", + "lib/netcoreapp2.0/_._", + "lib/netstandard1.3/Microsoft.CSharp.dll", + "lib/netstandard2.0/Microsoft.CSharp.dll", + "lib/netstandard2.0/Microsoft.CSharp.xml", + "lib/portable-net45+win8+wp8+wpa81/_._", + "lib/uap10.0.16299/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "microsoft.csharp.4.7.0.nupkg.sha512", + "microsoft.csharp.nuspec", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/Microsoft.CSharp.dll", + "ref/netcore50/Microsoft.CSharp.xml", + "ref/netcore50/de/Microsoft.CSharp.xml", + "ref/netcore50/es/Microsoft.CSharp.xml", + "ref/netcore50/fr/Microsoft.CSharp.xml", + "ref/netcore50/it/Microsoft.CSharp.xml", + "ref/netcore50/ja/Microsoft.CSharp.xml", + "ref/netcore50/ko/Microsoft.CSharp.xml", + "ref/netcore50/ru/Microsoft.CSharp.xml", + "ref/netcore50/zh-hans/Microsoft.CSharp.xml", + "ref/netcore50/zh-hant/Microsoft.CSharp.xml", + "ref/netcoreapp2.0/_._", + "ref/netstandard1.0/Microsoft.CSharp.dll", + "ref/netstandard1.0/Microsoft.CSharp.xml", + "ref/netstandard1.0/de/Microsoft.CSharp.xml", + "ref/netstandard1.0/es/Microsoft.CSharp.xml", + "ref/netstandard1.0/fr/Microsoft.CSharp.xml", + "ref/netstandard1.0/it/Microsoft.CSharp.xml", + "ref/netstandard1.0/ja/Microsoft.CSharp.xml", + "ref/netstandard1.0/ko/Microsoft.CSharp.xml", + "ref/netstandard1.0/ru/Microsoft.CSharp.xml", + "ref/netstandard1.0/zh-hans/Microsoft.CSharp.xml", + "ref/netstandard1.0/zh-hant/Microsoft.CSharp.xml", + "ref/netstandard2.0/Microsoft.CSharp.dll", + "ref/netstandard2.0/Microsoft.CSharp.xml", + "ref/portable-net45+win8+wp8+wpa81/_._", + "ref/uap10.0.16299/_._", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "Microsoft.Extensions.ApiDescription.Server/6.0.3": { + "sha512": "/FkS66n3wJaUR+Grkg+dMMIyrfmfkEybNoyOhdBMURxavPx6Q1Kn7NY5Ho41s975gpXA9Pnw7WRJbxwICLFgbw==", + "type": "package", + "path": "microsoft.extensions.apidescription.server/6.0.3", + "hasTools": true, + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "build/Microsoft.Extensions.ApiDescription.Server.props", + "build/Microsoft.Extensions.ApiDescription.Server.targets", + "buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.props", + "buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.targets", + "microsoft.extensions.apidescription.server.6.0.3.nupkg.sha512", + "microsoft.extensions.apidescription.server.nuspec", + "tools/Newtonsoft.Json.dll", + "tools/dotnet-getdocument.deps.json", + "tools/dotnet-getdocument.dll", + "tools/dotnet-getdocument.runtimeconfig.json", + "tools/net461-x86/GetDocument.Insider.exe", + "tools/net461-x86/GetDocument.Insider.exe.config", + "tools/net461-x86/Microsoft.Win32.Primitives.dll", + "tools/net461-x86/System.AppContext.dll", + "tools/net461-x86/System.Buffers.dll", + "tools/net461-x86/System.Collections.Concurrent.dll", + "tools/net461-x86/System.Collections.NonGeneric.dll", + "tools/net461-x86/System.Collections.Specialized.dll", + "tools/net461-x86/System.Collections.dll", + "tools/net461-x86/System.ComponentModel.EventBasedAsync.dll", + "tools/net461-x86/System.ComponentModel.Primitives.dll", + "tools/net461-x86/System.ComponentModel.TypeConverter.dll", + "tools/net461-x86/System.ComponentModel.dll", + "tools/net461-x86/System.Console.dll", + "tools/net461-x86/System.Data.Common.dll", + "tools/net461-x86/System.Diagnostics.Contracts.dll", + "tools/net461-x86/System.Diagnostics.Debug.dll", + "tools/net461-x86/System.Diagnostics.DiagnosticSource.dll", + "tools/net461-x86/System.Diagnostics.FileVersionInfo.dll", + "tools/net461-x86/System.Diagnostics.Process.dll", + "tools/net461-x86/System.Diagnostics.StackTrace.dll", + "tools/net461-x86/System.Diagnostics.TextWriterTraceListener.dll", + "tools/net461-x86/System.Diagnostics.Tools.dll", + "tools/net461-x86/System.Diagnostics.TraceSource.dll", + "tools/net461-x86/System.Diagnostics.Tracing.dll", + "tools/net461-x86/System.Drawing.Primitives.dll", + "tools/net461-x86/System.Dynamic.Runtime.dll", + "tools/net461-x86/System.Globalization.Calendars.dll", + "tools/net461-x86/System.Globalization.Extensions.dll", + "tools/net461-x86/System.Globalization.dll", + "tools/net461-x86/System.IO.Compression.ZipFile.dll", + "tools/net461-x86/System.IO.Compression.dll", + "tools/net461-x86/System.IO.FileSystem.DriveInfo.dll", + "tools/net461-x86/System.IO.FileSystem.Primitives.dll", + "tools/net461-x86/System.IO.FileSystem.Watcher.dll", + "tools/net461-x86/System.IO.FileSystem.dll", + "tools/net461-x86/System.IO.IsolatedStorage.dll", + "tools/net461-x86/System.IO.MemoryMappedFiles.dll", + "tools/net461-x86/System.IO.Pipes.dll", + "tools/net461-x86/System.IO.UnmanagedMemoryStream.dll", + "tools/net461-x86/System.IO.dll", + "tools/net461-x86/System.Linq.Expressions.dll", + "tools/net461-x86/System.Linq.Parallel.dll", + "tools/net461-x86/System.Linq.Queryable.dll", + "tools/net461-x86/System.Linq.dll", + "tools/net461-x86/System.Memory.dll", + "tools/net461-x86/System.Net.Http.dll", + "tools/net461-x86/System.Net.NameResolution.dll", + "tools/net461-x86/System.Net.NetworkInformation.dll", + "tools/net461-x86/System.Net.Ping.dll", + "tools/net461-x86/System.Net.Primitives.dll", + "tools/net461-x86/System.Net.Requests.dll", + "tools/net461-x86/System.Net.Security.dll", + "tools/net461-x86/System.Net.Sockets.dll", + "tools/net461-x86/System.Net.WebHeaderCollection.dll", + "tools/net461-x86/System.Net.WebSockets.Client.dll", + "tools/net461-x86/System.Net.WebSockets.dll", + "tools/net461-x86/System.Numerics.Vectors.dll", + "tools/net461-x86/System.ObjectModel.dll", + "tools/net461-x86/System.Reflection.Extensions.dll", + "tools/net461-x86/System.Reflection.Primitives.dll", + "tools/net461-x86/System.Reflection.dll", + "tools/net461-x86/System.Resources.Reader.dll", + "tools/net461-x86/System.Resources.ResourceManager.dll", + "tools/net461-x86/System.Resources.Writer.dll", + "tools/net461-x86/System.Runtime.CompilerServices.Unsafe.dll", + "tools/net461-x86/System.Runtime.CompilerServices.VisualC.dll", + "tools/net461-x86/System.Runtime.Extensions.dll", + "tools/net461-x86/System.Runtime.Handles.dll", + "tools/net461-x86/System.Runtime.InteropServices.RuntimeInformation.dll", + "tools/net461-x86/System.Runtime.InteropServices.dll", + "tools/net461-x86/System.Runtime.Numerics.dll", + "tools/net461-x86/System.Runtime.Serialization.Formatters.dll", + "tools/net461-x86/System.Runtime.Serialization.Json.dll", + "tools/net461-x86/System.Runtime.Serialization.Primitives.dll", + "tools/net461-x86/System.Runtime.Serialization.Xml.dll", + "tools/net461-x86/System.Runtime.dll", + "tools/net461-x86/System.Security.Claims.dll", + "tools/net461-x86/System.Security.Cryptography.Algorithms.dll", + "tools/net461-x86/System.Security.Cryptography.Csp.dll", + "tools/net461-x86/System.Security.Cryptography.Encoding.dll", + "tools/net461-x86/System.Security.Cryptography.Primitives.dll", + "tools/net461-x86/System.Security.Cryptography.X509Certificates.dll", + "tools/net461-x86/System.Security.Principal.dll", + "tools/net461-x86/System.Security.SecureString.dll", + "tools/net461-x86/System.Text.Encoding.Extensions.dll", + "tools/net461-x86/System.Text.Encoding.dll", + "tools/net461-x86/System.Text.RegularExpressions.dll", + "tools/net461-x86/System.Threading.Overlapped.dll", + "tools/net461-x86/System.Threading.Tasks.Parallel.dll", + "tools/net461-x86/System.Threading.Tasks.dll", + "tools/net461-x86/System.Threading.Thread.dll", + "tools/net461-x86/System.Threading.ThreadPool.dll", + "tools/net461-x86/System.Threading.Timer.dll", + "tools/net461-x86/System.Threading.dll", + "tools/net461-x86/System.ValueTuple.dll", + "tools/net461-x86/System.Xml.ReaderWriter.dll", + "tools/net461-x86/System.Xml.XDocument.dll", + "tools/net461-x86/System.Xml.XPath.XDocument.dll", + "tools/net461-x86/System.Xml.XPath.dll", + "tools/net461-x86/System.Xml.XmlDocument.dll", + "tools/net461-x86/System.Xml.XmlSerializer.dll", + "tools/net461-x86/netstandard.dll", + "tools/net461/GetDocument.Insider.exe", + "tools/net461/GetDocument.Insider.exe.config", + "tools/net461/Microsoft.Win32.Primitives.dll", + "tools/net461/System.AppContext.dll", + "tools/net461/System.Buffers.dll", + "tools/net461/System.Collections.Concurrent.dll", + "tools/net461/System.Collections.NonGeneric.dll", + "tools/net461/System.Collections.Specialized.dll", + "tools/net461/System.Collections.dll", + "tools/net461/System.ComponentModel.EventBasedAsync.dll", + "tools/net461/System.ComponentModel.Primitives.dll", + "tools/net461/System.ComponentModel.TypeConverter.dll", + "tools/net461/System.ComponentModel.dll", + "tools/net461/System.Console.dll", + "tools/net461/System.Data.Common.dll", + "tools/net461/System.Diagnostics.Contracts.dll", + "tools/net461/System.Diagnostics.Debug.dll", + "tools/net461/System.Diagnostics.DiagnosticSource.dll", + "tools/net461/System.Diagnostics.FileVersionInfo.dll", + "tools/net461/System.Diagnostics.Process.dll", + "tools/net461/System.Diagnostics.StackTrace.dll", + "tools/net461/System.Diagnostics.TextWriterTraceListener.dll", + "tools/net461/System.Diagnostics.Tools.dll", + "tools/net461/System.Diagnostics.TraceSource.dll", + "tools/net461/System.Diagnostics.Tracing.dll", + "tools/net461/System.Drawing.Primitives.dll", + "tools/net461/System.Dynamic.Runtime.dll", + "tools/net461/System.Globalization.Calendars.dll", + "tools/net461/System.Globalization.Extensions.dll", + "tools/net461/System.Globalization.dll", + "tools/net461/System.IO.Compression.ZipFile.dll", + "tools/net461/System.IO.Compression.dll", + "tools/net461/System.IO.FileSystem.DriveInfo.dll", + "tools/net461/System.IO.FileSystem.Primitives.dll", + "tools/net461/System.IO.FileSystem.Watcher.dll", + "tools/net461/System.IO.FileSystem.dll", + "tools/net461/System.IO.IsolatedStorage.dll", + "tools/net461/System.IO.MemoryMappedFiles.dll", + "tools/net461/System.IO.Pipes.dll", + "tools/net461/System.IO.UnmanagedMemoryStream.dll", + "tools/net461/System.IO.dll", + "tools/net461/System.Linq.Expressions.dll", + "tools/net461/System.Linq.Parallel.dll", + "tools/net461/System.Linq.Queryable.dll", + "tools/net461/System.Linq.dll", + "tools/net461/System.Memory.dll", + "tools/net461/System.Net.Http.dll", + "tools/net461/System.Net.NameResolution.dll", + "tools/net461/System.Net.NetworkInformation.dll", + "tools/net461/System.Net.Ping.dll", + "tools/net461/System.Net.Primitives.dll", + "tools/net461/System.Net.Requests.dll", + "tools/net461/System.Net.Security.dll", + "tools/net461/System.Net.Sockets.dll", + "tools/net461/System.Net.WebHeaderCollection.dll", + "tools/net461/System.Net.WebSockets.Client.dll", + "tools/net461/System.Net.WebSockets.dll", + "tools/net461/System.Numerics.Vectors.dll", + "tools/net461/System.ObjectModel.dll", + "tools/net461/System.Reflection.Extensions.dll", + "tools/net461/System.Reflection.Primitives.dll", + "tools/net461/System.Reflection.dll", + "tools/net461/System.Resources.Reader.dll", + "tools/net461/System.Resources.ResourceManager.dll", + "tools/net461/System.Resources.Writer.dll", + "tools/net461/System.Runtime.CompilerServices.Unsafe.dll", + "tools/net461/System.Runtime.CompilerServices.VisualC.dll", + "tools/net461/System.Runtime.Extensions.dll", + "tools/net461/System.Runtime.Handles.dll", + "tools/net461/System.Runtime.InteropServices.RuntimeInformation.dll", + "tools/net461/System.Runtime.InteropServices.dll", + "tools/net461/System.Runtime.Numerics.dll", + "tools/net461/System.Runtime.Serialization.Formatters.dll", + "tools/net461/System.Runtime.Serialization.Json.dll", + "tools/net461/System.Runtime.Serialization.Primitives.dll", + "tools/net461/System.Runtime.Serialization.Xml.dll", + "tools/net461/System.Runtime.dll", + "tools/net461/System.Security.Claims.dll", + "tools/net461/System.Security.Cryptography.Algorithms.dll", + "tools/net461/System.Security.Cryptography.Csp.dll", + "tools/net461/System.Security.Cryptography.Encoding.dll", + "tools/net461/System.Security.Cryptography.Primitives.dll", + "tools/net461/System.Security.Cryptography.X509Certificates.dll", + "tools/net461/System.Security.Principal.dll", + "tools/net461/System.Security.SecureString.dll", + "tools/net461/System.Text.Encoding.Extensions.dll", + "tools/net461/System.Text.Encoding.dll", + "tools/net461/System.Text.RegularExpressions.dll", + "tools/net461/System.Threading.Overlapped.dll", + "tools/net461/System.Threading.Tasks.Parallel.dll", + "tools/net461/System.Threading.Tasks.dll", + "tools/net461/System.Threading.Thread.dll", + "tools/net461/System.Threading.ThreadPool.dll", + "tools/net461/System.Threading.Timer.dll", + "tools/net461/System.Threading.dll", + "tools/net461/System.ValueTuple.dll", + "tools/net461/System.Xml.ReaderWriter.dll", + "tools/net461/System.Xml.XDocument.dll", + "tools/net461/System.Xml.XPath.XDocument.dll", + "tools/net461/System.Xml.XPath.dll", + "tools/net461/System.Xml.XmlDocument.dll", + "tools/net461/System.Xml.XmlSerializer.dll", + "tools/net461/netstandard.dll", + "tools/netcoreapp2.1/GetDocument.Insider.deps.json", + "tools/netcoreapp2.1/GetDocument.Insider.dll", + "tools/netcoreapp2.1/GetDocument.Insider.runtimeconfig.json", + "tools/netcoreapp2.1/System.Diagnostics.DiagnosticSource.dll" + ] + }, + "Microsoft.Extensions.Caching.Abstractions/8.0.0": { + "sha512": "3KuSxeHoNYdxVYfg2IRZCThcrlJ1XJqIXkAWikCsbm5C/bCjv7G0WoKDyuR98Q+T607QT2Zl5GsbGRkENcV2yQ==", + "type": "package", + "path": "microsoft.extensions.caching.abstractions/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Caching.Abstractions.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Caching.Abstractions.targets", + "lib/net462/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/net462/Microsoft.Extensions.Caching.Abstractions.xml", + "lib/net6.0/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/net6.0/Microsoft.Extensions.Caching.Abstractions.xml", + "lib/net7.0/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/net7.0/Microsoft.Extensions.Caching.Abstractions.xml", + "lib/net8.0/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/net8.0/Microsoft.Extensions.Caching.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Abstractions.xml", + "microsoft.extensions.caching.abstractions.8.0.0.nupkg.sha512", + "microsoft.extensions.caching.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Caching.Memory/8.0.1": { + "sha512": "HFDnhYLccngrzyGgHkjEDU5FMLn4MpOsr5ElgsBMC4yx6lJh4jeWO7fHS8+TXPq+dgxCmUa/Trl8svObmwW4QA==", + "type": "package", + "path": "microsoft.extensions.caching.memory/8.0.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Caching.Memory.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Caching.Memory.targets", + "lib/net462/Microsoft.Extensions.Caching.Memory.dll", + "lib/net462/Microsoft.Extensions.Caching.Memory.xml", + "lib/net6.0/Microsoft.Extensions.Caching.Memory.dll", + "lib/net6.0/Microsoft.Extensions.Caching.Memory.xml", + "lib/net7.0/Microsoft.Extensions.Caching.Memory.dll", + "lib/net7.0/Microsoft.Extensions.Caching.Memory.xml", + "lib/net8.0/Microsoft.Extensions.Caching.Memory.dll", + "lib/net8.0/Microsoft.Extensions.Caching.Memory.xml", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Memory.dll", + "lib/netstandard2.0/Microsoft.Extensions.Caching.Memory.xml", + "microsoft.extensions.caching.memory.8.0.1.nupkg.sha512", + "microsoft.extensions.caching.memory.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "sha512": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "type": "package", + "path": "microsoft.extensions.configuration/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Configuration.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Configuration.targets", + "lib/net462/Microsoft.Extensions.Configuration.dll", + "lib/net462/Microsoft.Extensions.Configuration.xml", + "lib/net6.0/Microsoft.Extensions.Configuration.dll", + "lib/net6.0/Microsoft.Extensions.Configuration.xml", + "lib/net7.0/Microsoft.Extensions.Configuration.dll", + "lib/net7.0/Microsoft.Extensions.Configuration.xml", + "lib/net8.0/Microsoft.Extensions.Configuration.dll", + "lib/net8.0/Microsoft.Extensions.Configuration.xml", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.dll", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.xml", + "microsoft.extensions.configuration.8.0.0.nupkg.sha512", + "microsoft.extensions.configuration.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "sha512": "3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "type": "package", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Configuration.Abstractions.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Configuration.Abstractions.targets", + "lib/net462/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/net462/Microsoft.Extensions.Configuration.Abstractions.xml", + "lib/net6.0/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/net6.0/Microsoft.Extensions.Configuration.Abstractions.xml", + "lib/net7.0/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/net7.0/Microsoft.Extensions.Configuration.Abstractions.xml", + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.xml", + "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512", + "microsoft.extensions.configuration.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Configuration.Binder/8.0.0": { + "sha512": "mBMoXLsr5s1y2zOHWmKsE9veDcx8h1x/c3rz4baEdQKTeDcmQAPNbB54Pi/lhFO3K431eEq6PFbMgLaa6PHFfA==", + "type": "package", + "path": "microsoft.extensions.configuration.binder/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "analyzers/dotnet/cs/Microsoft.Extensions.Configuration.Binder.SourceGeneration.dll", + "analyzers/dotnet/cs/cs/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/de/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/es/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/fr/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/it/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/ja/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/ko/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/pl/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/pt-BR/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/ru/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/tr/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/zh-Hans/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "analyzers/dotnet/cs/zh-Hant/Microsoft.Extensions.Configuration.Binder.SourceGeneration.resources.dll", + "buildTransitive/netstandard2.0/Microsoft.Extensions.Configuration.Binder.targets", + "lib/net462/Microsoft.Extensions.Configuration.Binder.dll", + "lib/net462/Microsoft.Extensions.Configuration.Binder.xml", + "lib/net6.0/Microsoft.Extensions.Configuration.Binder.dll", + "lib/net6.0/Microsoft.Extensions.Configuration.Binder.xml", + "lib/net7.0/Microsoft.Extensions.Configuration.Binder.dll", + "lib/net7.0/Microsoft.Extensions.Configuration.Binder.xml", + "lib/net8.0/Microsoft.Extensions.Configuration.Binder.dll", + "lib/net8.0/Microsoft.Extensions.Configuration.Binder.xml", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Binder.dll", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Binder.xml", + "microsoft.extensions.configuration.binder.8.0.0.nupkg.sha512", + "microsoft.extensions.configuration.binder.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "sha512": "McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", + "type": "package", + "path": "microsoft.extensions.configuration.fileextensions/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Configuration.FileExtensions.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Configuration.FileExtensions.targets", + "lib/net462/Microsoft.Extensions.Configuration.FileExtensions.dll", + "lib/net462/Microsoft.Extensions.Configuration.FileExtensions.xml", + "lib/net6.0/Microsoft.Extensions.Configuration.FileExtensions.dll", + "lib/net6.0/Microsoft.Extensions.Configuration.FileExtensions.xml", + "lib/net7.0/Microsoft.Extensions.Configuration.FileExtensions.dll", + "lib/net7.0/Microsoft.Extensions.Configuration.FileExtensions.xml", + "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll", + "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.xml", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.FileExtensions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.FileExtensions.xml", + "microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512", + "microsoft.extensions.configuration.fileextensions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "sha512": "C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", + "type": "package", + "path": "microsoft.extensions.configuration.json/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Configuration.Json.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Configuration.Json.targets", + "lib/net462/Microsoft.Extensions.Configuration.Json.dll", + "lib/net462/Microsoft.Extensions.Configuration.Json.xml", + "lib/net6.0/Microsoft.Extensions.Configuration.Json.dll", + "lib/net6.0/Microsoft.Extensions.Configuration.Json.xml", + "lib/net7.0/Microsoft.Extensions.Configuration.Json.dll", + "lib/net7.0/Microsoft.Extensions.Configuration.Json.xml", + "lib/net8.0/Microsoft.Extensions.Configuration.Json.dll", + "lib/net8.0/Microsoft.Extensions.Configuration.Json.xml", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Json.dll", + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Json.xml", + "lib/netstandard2.1/Microsoft.Extensions.Configuration.Json.dll", + "lib/netstandard2.1/Microsoft.Extensions.Configuration.Json.xml", + "microsoft.extensions.configuration.json.8.0.0.nupkg.sha512", + "microsoft.extensions.configuration.json.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.DependencyInjection/6.0.0": { + "sha512": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==", + "type": "package", + "path": "microsoft.extensions.dependencyinjection/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.DependencyInjection.targets", + "buildTransitive/netcoreapp3.1/_._", + "lib/net461/Microsoft.Extensions.DependencyInjection.dll", + "lib/net461/Microsoft.Extensions.DependencyInjection.xml", + "lib/net6.0/Microsoft.Extensions.DependencyInjection.dll", + "lib/net6.0/Microsoft.Extensions.DependencyInjection.xml", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.dll", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.xml", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.dll", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.xml", + "microsoft.extensions.dependencyinjection.6.0.0.nupkg.sha512", + "microsoft.extensions.dependencyinjection.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.2": { + "sha512": "3iE7UF7MQkCv1cxzCahz+Y/guQbTqieyxyaWKhrRO91itI9cOKO76OHeQDahqG4MmW5umr3CcCvGmK92lWNlbg==", + "type": "package", + "path": "microsoft.extensions.dependencyinjection.abstractions/8.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.DependencyInjection.Abstractions.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.DependencyInjection.Abstractions.targets", + "lib/net462/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/net462/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/net7.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/net7.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.Abstractions.xml", + "microsoft.extensions.dependencyinjection.abstractions.8.0.2.nupkg.sha512", + "microsoft.extensions.dependencyinjection.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "sha512": "ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", + "type": "package", + "path": "microsoft.extensions.fileproviders.abstractions/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.FileProviders.Abstractions.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.FileProviders.Abstractions.targets", + "lib/net462/Microsoft.Extensions.FileProviders.Abstractions.dll", + "lib/net462/Microsoft.Extensions.FileProviders.Abstractions.xml", + "lib/net6.0/Microsoft.Extensions.FileProviders.Abstractions.dll", + "lib/net6.0/Microsoft.Extensions.FileProviders.Abstractions.xml", + "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll", + "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.xml", + "microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512", + "microsoft.extensions.fileproviders.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.FileProviders.Embedded/6.0.0": { + "sha512": "9uQbDTqX1MidhoZFUSK1JItt74IapEadFDOIWAlBIKxr3O/ZEWLWkLYGlgUeP1Dkyog6/CB7h1EAU3xADYZ/lA==", + "type": "package", + "path": "microsoft.extensions.fileproviders.embedded/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "build/netstandard2.0/Microsoft.Extensions.FileProviders.Embedded.props", + "build/netstandard2.0/Microsoft.Extensions.FileProviders.Embedded.targets", + "buildMultiTargeting/Microsoft.Extensions.FileProviders.Embedded.props", + "buildMultiTargeting/Microsoft.Extensions.FileProviders.Embedded.targets", + "lib/net461/Microsoft.Extensions.FileProviders.Embedded.dll", + "lib/net461/Microsoft.Extensions.FileProviders.Embedded.xml", + "lib/net6.0/Microsoft.Extensions.FileProviders.Embedded.dll", + "lib/net6.0/Microsoft.Extensions.FileProviders.Embedded.xml", + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Embedded.dll", + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Embedded.xml", + "microsoft.extensions.fileproviders.embedded.6.0.0.nupkg.sha512", + "microsoft.extensions.fileproviders.embedded.nuspec", + "tasks/netstandard2.0/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.dll" + ] + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "sha512": "UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", + "type": "package", + "path": "microsoft.extensions.fileproviders.physical/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.FileProviders.Physical.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.FileProviders.Physical.targets", + "lib/net462/Microsoft.Extensions.FileProviders.Physical.dll", + "lib/net462/Microsoft.Extensions.FileProviders.Physical.xml", + "lib/net6.0/Microsoft.Extensions.FileProviders.Physical.dll", + "lib/net6.0/Microsoft.Extensions.FileProviders.Physical.xml", + "lib/net7.0/Microsoft.Extensions.FileProviders.Physical.dll", + "lib/net7.0/Microsoft.Extensions.FileProviders.Physical.xml", + "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll", + "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.xml", + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Physical.dll", + "lib/netstandard2.0/Microsoft.Extensions.FileProviders.Physical.xml", + "microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512", + "microsoft.extensions.fileproviders.physical.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "sha512": "OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==", + "type": "package", + "path": "microsoft.extensions.filesystemglobbing/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.FileSystemGlobbing.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.FileSystemGlobbing.targets", + "lib/net462/Microsoft.Extensions.FileSystemGlobbing.dll", + "lib/net462/Microsoft.Extensions.FileSystemGlobbing.xml", + "lib/net6.0/Microsoft.Extensions.FileSystemGlobbing.dll", + "lib/net6.0/Microsoft.Extensions.FileSystemGlobbing.xml", + "lib/net7.0/Microsoft.Extensions.FileSystemGlobbing.dll", + "lib/net7.0/Microsoft.Extensions.FileSystemGlobbing.xml", + "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll", + "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.xml", + "lib/netstandard2.0/Microsoft.Extensions.FileSystemGlobbing.dll", + "lib/netstandard2.0/Microsoft.Extensions.FileSystemGlobbing.xml", + "microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512", + "microsoft.extensions.filesystemglobbing.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Hosting.Abstractions/6.0.0": { + "sha512": "GcT5l2CYXL6Sa27KCSh0TixsRfADUgth+ojQSD5EkzisZxmGFh7CwzkcYuGwvmXLjr27uWRNrJ2vuuEjMhU05Q==", + "type": "package", + "path": "microsoft.extensions.hosting.abstractions/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/Microsoft.Extensions.Hosting.Abstractions.dll", + "lib/net461/Microsoft.Extensions.Hosting.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.Hosting.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Hosting.Abstractions.xml", + "lib/netstandard2.1/Microsoft.Extensions.Hosting.Abstractions.dll", + "lib/netstandard2.1/Microsoft.Extensions.Hosting.Abstractions.xml", + "microsoft.extensions.hosting.abstractions.6.0.0.nupkg.sha512", + "microsoft.extensions.hosting.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Http/6.0.0": { + "sha512": "15+pa2G0bAMHbHewaQIdr/y6ag2H3yh4rd9hTXavtWDzQBkvpe2RMqFg8BxDpcQWssmjmBApGPcw93QRz6YcMg==", + "type": "package", + "path": "microsoft.extensions.http/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/Microsoft.Extensions.Http.dll", + "lib/net461/Microsoft.Extensions.Http.xml", + "lib/netstandard2.0/Microsoft.Extensions.Http.dll", + "lib/netstandard2.0/Microsoft.Extensions.Http.xml", + "microsoft.extensions.http.6.0.0.nupkg.sha512", + "microsoft.extensions.http.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Logging/6.0.0": { + "sha512": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==", + "type": "package", + "path": "microsoft.extensions.logging/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/Microsoft.Extensions.Logging.dll", + "lib/net461/Microsoft.Extensions.Logging.xml", + "lib/netstandard2.0/Microsoft.Extensions.Logging.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.xml", + "lib/netstandard2.1/Microsoft.Extensions.Logging.dll", + "lib/netstandard2.1/Microsoft.Extensions.Logging.xml", + "microsoft.extensions.logging.6.0.0.nupkg.sha512", + "microsoft.extensions.logging.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Logging.Abstractions/8.0.2": { + "sha512": "nroMDjS7hNBPtkZqVBbSiQaQjWRDxITI8Y7XnDs97rqG3EbzVTNLZQf7bIeUJcaHOV8bca47s1Uxq94+2oGdxA==", + "type": "package", + "path": "microsoft.extensions.logging.abstractions/8.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "analyzers/dotnet/roslyn3.11/cs/Microsoft.Extensions.Logging.Generators.dll", + "analyzers/dotnet/roslyn3.11/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/Microsoft.Extensions.Logging.Generators.dll", + "analyzers/dotnet/roslyn4.0/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/Microsoft.Extensions.Logging.Generators.dll", + "analyzers/dotnet/roslyn4.4/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll", + "buildTransitive/net461/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/net462/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Logging.Abstractions.targets", + "buildTransitive/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.targets", + "lib/net462/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/net462/Microsoft.Extensions.Logging.Abstractions.xml", + "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/net6.0/Microsoft.Extensions.Logging.Abstractions.xml", + "lib/net7.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/net7.0/Microsoft.Extensions.Logging.Abstractions.xml", + "lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/net8.0/Microsoft.Extensions.Logging.Abstractions.xml", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml", + "microsoft.extensions.logging.abstractions.8.0.2.nupkg.sha512", + "microsoft.extensions.logging.abstractions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.ObjectPool/7.0.0": { + "sha512": "udvKco0sAVgYGTBnHUb0tY9JQzJ/nPDiv/8PIyz69wl1AibeCDZOLVVI+6156dPfHmJH7ws5oUJRiW4ZmAvuuA==", + "type": "package", + "path": "microsoft.extensions.objectpool/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "THIRD-PARTY-NOTICES.TXT", + "lib/net462/Microsoft.Extensions.ObjectPool.dll", + "lib/net462/Microsoft.Extensions.ObjectPool.xml", + "lib/net7.0/Microsoft.Extensions.ObjectPool.dll", + "lib/net7.0/Microsoft.Extensions.ObjectPool.xml", + "lib/netstandard2.0/Microsoft.Extensions.ObjectPool.dll", + "lib/netstandard2.0/Microsoft.Extensions.ObjectPool.xml", + "microsoft.extensions.objectpool.7.0.0.nupkg.sha512", + "microsoft.extensions.objectpool.nuspec" + ] + }, + "Microsoft.Extensions.Options/8.0.2": { + "sha512": "dWGKvhFybsaZpGmzkGCbNNwBD1rVlWzrZKANLW/CcbFJpCEceMCGzT7zZwHOGBCbwM0SzBuceMj5HN1LKV1QqA==", + "type": "package", + "path": "microsoft.extensions.options/8.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "analyzers/dotnet/roslyn4.4/cs/Microsoft.Extensions.Options.SourceGeneration.dll", + "analyzers/dotnet/roslyn4.4/cs/cs/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/de/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/es/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/fr/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/it/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ja/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ko/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/pl/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/pt-BR/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ru/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/tr/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/zh-Hans/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/zh-Hant/Microsoft.Extensions.Options.SourceGeneration.resources.dll", + "buildTransitive/net461/Microsoft.Extensions.Options.targets", + "buildTransitive/net462/Microsoft.Extensions.Options.targets", + "buildTransitive/net6.0/Microsoft.Extensions.Options.targets", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Options.targets", + "buildTransitive/netstandard2.0/Microsoft.Extensions.Options.targets", + "lib/net462/Microsoft.Extensions.Options.dll", + "lib/net462/Microsoft.Extensions.Options.xml", + "lib/net6.0/Microsoft.Extensions.Options.dll", + "lib/net6.0/Microsoft.Extensions.Options.xml", + "lib/net7.0/Microsoft.Extensions.Options.dll", + "lib/net7.0/Microsoft.Extensions.Options.xml", + "lib/net8.0/Microsoft.Extensions.Options.dll", + "lib/net8.0/Microsoft.Extensions.Options.xml", + "lib/netstandard2.0/Microsoft.Extensions.Options.dll", + "lib/netstandard2.0/Microsoft.Extensions.Options.xml", + "lib/netstandard2.1/Microsoft.Extensions.Options.dll", + "lib/netstandard2.1/Microsoft.Extensions.Options.xml", + "microsoft.extensions.options.8.0.2.nupkg.sha512", + "microsoft.extensions.options.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Options.ConfigurationExtensions/8.0.0": { + "sha512": "0f4DMRqEd50zQh+UyJc+/HiBsZ3vhAQALgdkcQEalSH1L2isdC7Yj54M3cyo5e+BeO5fcBQ7Dxly8XiBBcvRgw==", + "type": "package", + "path": "microsoft.extensions.options.configurationextensions/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Options.ConfigurationExtensions.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Options.ConfigurationExtensions.targets", + "lib/net462/Microsoft.Extensions.Options.ConfigurationExtensions.dll", + "lib/net462/Microsoft.Extensions.Options.ConfigurationExtensions.xml", + "lib/net6.0/Microsoft.Extensions.Options.ConfigurationExtensions.dll", + "lib/net6.0/Microsoft.Extensions.Options.ConfigurationExtensions.xml", + "lib/net7.0/Microsoft.Extensions.Options.ConfigurationExtensions.dll", + "lib/net7.0/Microsoft.Extensions.Options.ConfigurationExtensions.xml", + "lib/net8.0/Microsoft.Extensions.Options.ConfigurationExtensions.dll", + "lib/net8.0/Microsoft.Extensions.Options.ConfigurationExtensions.xml", + "lib/netstandard2.0/Microsoft.Extensions.Options.ConfigurationExtensions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Options.ConfigurationExtensions.xml", + "microsoft.extensions.options.configurationextensions.8.0.0.nupkg.sha512", + "microsoft.extensions.options.configurationextensions.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "sha512": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "type": "package", + "path": "microsoft.extensions.primitives/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/Microsoft.Extensions.Primitives.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/Microsoft.Extensions.Primitives.targets", + "lib/net462/Microsoft.Extensions.Primitives.dll", + "lib/net462/Microsoft.Extensions.Primitives.xml", + "lib/net6.0/Microsoft.Extensions.Primitives.dll", + "lib/net6.0/Microsoft.Extensions.Primitives.xml", + "lib/net7.0/Microsoft.Extensions.Primitives.dll", + "lib/net7.0/Microsoft.Extensions.Primitives.xml", + "lib/net8.0/Microsoft.Extensions.Primitives.dll", + "lib/net8.0/Microsoft.Extensions.Primitives.xml", + "lib/netstandard2.0/Microsoft.Extensions.Primitives.dll", + "lib/netstandard2.0/Microsoft.Extensions.Primitives.xml", + "microsoft.extensions.primitives.8.0.0.nupkg.sha512", + "microsoft.extensions.primitives.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "Microsoft.IO.RecyclableMemoryStream/3.0.0": { + "sha512": "irv0HuqoH8Ig5i2fO+8dmDNdFdsrO+DoQcedwIlb810qpZHBNQHZLW7C/AHBQDgLLpw2T96vmMAy/aE4Yj55Sg==", + "type": "package", + "path": "microsoft.io.recyclablememorystream/3.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net6.0/Microsoft.IO.RecyclableMemoryStream.dll", + "lib/net6.0/Microsoft.IO.RecyclableMemoryStream.xml", + "lib/netstandard2.0/Microsoft.IO.RecyclableMemoryStream.dll", + "lib/netstandard2.0/Microsoft.IO.RecyclableMemoryStream.xml", + "lib/netstandard2.1/Microsoft.IO.RecyclableMemoryStream.dll", + "lib/netstandard2.1/Microsoft.IO.RecyclableMemoryStream.xml", + "microsoft.io.recyclablememorystream.3.0.0.nupkg.sha512", + "microsoft.io.recyclablememorystream.nuspec" + ] + }, + "Microsoft.NETCore.Platforms/1.1.0": { + "sha512": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==", + "type": "package", + "path": "microsoft.netcore.platforms/1.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/netstandard1.0/_._", + "microsoft.netcore.platforms.1.1.0.nupkg.sha512", + "microsoft.netcore.platforms.nuspec", + "runtime.json" + ] + }, + "Microsoft.NETCore.Targets/1.1.0": { + "sha512": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==", + "type": "package", + "path": "microsoft.netcore.targets/1.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/netstandard1.0/_._", + "microsoft.netcore.targets.1.1.0.nupkg.sha512", + "microsoft.netcore.targets.nuspec", + "runtime.json" + ] + }, + "Microsoft.Win32.Primitives/4.3.0": { + "sha512": "9ZQKCWxH7Ijp9BfahvL2Zyf1cJIk8XYLF6Yjzr2yi0b2cOut/HQ31qf1ThHAgCc3WiZMdnWcfJCgN82/0UunxA==", + "type": "package", + "path": "microsoft.win32.primitives/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/Microsoft.Win32.Primitives.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "microsoft.win32.primitives.4.3.0.nupkg.sha512", + "microsoft.win32.primitives.nuspec", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/Microsoft.Win32.Primitives.dll", + "ref/netstandard1.3/Microsoft.Win32.Primitives.dll", + "ref/netstandard1.3/Microsoft.Win32.Primitives.xml", + "ref/netstandard1.3/de/Microsoft.Win32.Primitives.xml", + "ref/netstandard1.3/es/Microsoft.Win32.Primitives.xml", + "ref/netstandard1.3/fr/Microsoft.Win32.Primitives.xml", + "ref/netstandard1.3/it/Microsoft.Win32.Primitives.xml", + "ref/netstandard1.3/ja/Microsoft.Win32.Primitives.xml", + "ref/netstandard1.3/ko/Microsoft.Win32.Primitives.xml", + "ref/netstandard1.3/ru/Microsoft.Win32.Primitives.xml", + "ref/netstandard1.3/zh-hans/Microsoft.Win32.Primitives.xml", + "ref/netstandard1.3/zh-hant/Microsoft.Win32.Primitives.xml", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._" + ] + }, + "Microsoft.Win32.Registry/4.3.0": { + "sha512": "Lw1/VwLH1yxz6SfFEjVRCN0pnflLEsWgnV4qsdJ512/HhTwnKXUG+zDQ4yTO3K/EJQemGoNaBHX5InISNKTzUQ==", + "type": "package", + "path": "microsoft.win32.registry/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/net46/Microsoft.Win32.Registry.dll", + "microsoft.win32.registry.4.3.0.nupkg.sha512", + "microsoft.win32.registry.nuspec", + "ref/net46/Microsoft.Win32.Registry.dll", + "ref/netstandard1.3/Microsoft.Win32.Registry.dll", + "ref/netstandard1.3/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/de/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/es/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/fr/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/it/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ja/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ko/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ru/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hans/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hant/Microsoft.Win32.Registry.xml", + "runtimes/unix/lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net46/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netcore50/_._", + "runtimes/win/lib/netstandard1.3/Microsoft.Win32.Registry.dll" + ] + }, + "MimeKit/3.5.0": { + "sha512": "XHRxnUJjNC6ufN94Yixp0QaLAZL+4L3huwzBhG5grBn68FQo3lH24gHKl15ceK4ktsALTqxdKPc/iMbQ442CGA==", + "type": "package", + "path": "mimekit/3.5.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "icons/mimekit-50.png", + "lib/net462/MimeKit.dll", + "lib/net462/MimeKit.pdb", + "lib/net462/MimeKit.xml", + "lib/net47/MimeKit.dll", + "lib/net47/MimeKit.pdb", + "lib/net47/MimeKit.xml", + "lib/net48/MimeKit.dll", + "lib/net48/MimeKit.pdb", + "lib/net48/MimeKit.xml", + "lib/net6.0/MimeKit.dll", + "lib/net6.0/MimeKit.pdb", + "lib/net6.0/MimeKit.xml", + "lib/netstandard2.0/MimeKit.dll", + "lib/netstandard2.0/MimeKit.pdb", + "lib/netstandard2.0/MimeKit.xml", + "lib/netstandard2.1/MimeKit.dll", + "lib/netstandard2.1/MimeKit.pdb", + "lib/netstandard2.1/MimeKit.xml", + "mimekit.3.5.0.nupkg.sha512", + "mimekit.nuspec" + ] + }, + "Namotion.Reflection/3.1.1": { + "sha512": "Qn0wM7u9TpSpja2x8UVexr2bLHb1DGMNhD2TCz3woklxaY1oH+Sitrw9fg/4YbNoNtczeH2jf+yPdXMQlgvFlQ==", + "type": "package", + "path": "namotion.reflection/3.1.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/Namotion.Reflection.dll", + "lib/net462/Namotion.Reflection.xml", + "lib/netstandard2.0/Namotion.Reflection.dll", + "lib/netstandard2.0/Namotion.Reflection.xml", + "namotion.reflection.3.1.1.nupkg.sha512", + "namotion.reflection.nuspec" + ] + }, + "NBitcoin/7.0.42": { + "sha512": "pN4d5MdYs/iYSZ++3fqN+Mw62cI1Ch7lY1G5gL3Dhnt2jW4aazGkvUZCTmr0YNUcWcWvSuTgivhfXLmPCjBsNw==", + "type": "package", + "path": "nbitcoin/7.0.42", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "icon.png", + "lib/net472/NBitcoin.dll", + "lib/net472/NBitcoin.xml", + "lib/net6.0/NBitcoin.dll", + "lib/net6.0/NBitcoin.xml", + "lib/netstandard1.1/NBitcoin.dll", + "lib/netstandard1.1/NBitcoin.xml", + "lib/netstandard1.3/NBitcoin.dll", + "lib/netstandard1.3/NBitcoin.xml", + "lib/netstandard2.0/NBitcoin.dll", + "lib/netstandard2.0/NBitcoin.xml", + "lib/netstandard2.1/NBitcoin.dll", + "lib/netstandard2.1/NBitcoin.xml", + "nbitcoin.7.0.42.nupkg.sha512", + "nbitcoin.nuspec" + ] + }, + "NBitcoin.Altcoins/3.0.28": { + "sha512": "LOXPsvmg98ZsALads+zuc1C4R02uUOSHfmP8lprrUnu0Z/AsRqb4X0pxwQf/5/MobQoTD33CLw/1LXuUw3m3HA==", + "type": "package", + "path": "nbitcoin.altcoins/3.0.28", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "icon.png", + "lib/net472/NBitcoin.Altcoins.dll", + "lib/net6.0/NBitcoin.Altcoins.dll", + "lib/netstandard1.3/NBitcoin.Altcoins.dll", + "lib/netstandard2.0/NBitcoin.Altcoins.dll", + "lib/netstandard2.1/NBitcoin.Altcoins.dll", + "nbitcoin.altcoins.3.0.28.nupkg.sha512", + "nbitcoin.altcoins.nuspec" + ] + }, + "NBitcoin.Secp256k1/3.1.6": { + "sha512": "Ao9jN/16lhQoI0aMdUxgiEfuyFdg2nd2SdinqqEFuCyYl1NH6upa++Tp0wbXHTr6jf7klXh3wjmsX+ArzliZRQ==", + "type": "package", + "path": "nbitcoin.secp256k1/3.1.6", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "icon.png", + "lib/net6.0/NBitcoin.Secp256k1.dll", + "lib/net6.0/NBitcoin.Secp256k1.xml", + "lib/netstandard2.1/NBitcoin.Secp256k1.dll", + "lib/netstandard2.1/NBitcoin.Secp256k1.xml", + "nbitcoin.secp256k1.3.1.6.nupkg.sha512", + "nbitcoin.secp256k1.nuspec" + ] + }, + "NBitcoin.Zcash/3.0.0": { + "sha512": "kZd5yK6c+Jev2D1RVj4yZOampv6CdrrDcPXqLgPuDFsz8D0thtcQ5rtB2YqW0VuKm3x9C5vib61pjNkxOA/V2g==", + "type": "package", + "path": "nbitcoin.zcash/3.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/NBitcoin.Zcash.dll", + "nbitcoin.zcash.3.0.0.nupkg.sha512", + "nbitcoin.zcash.nuspec" + ] + }, + "Newtonsoft.Json/13.0.3": { + "sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "type": "package", + "path": "newtonsoft.json/13.0.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "Newtonsoft.Json.Schema/4.0.1": { + "sha512": "rbHUKp5WTIbqmLEeJ21nTTDGcfR0LA7bVMzm0bYc3yx6NFKiCIHzzvYbwA4Sqgs7+wNldc5nBlkbithWj8IZig==", + "type": "package", + "path": "newtonsoft.json.schema/4.0.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net35/Newtonsoft.Json.Schema.dll", + "lib/net35/Newtonsoft.Json.Schema.xml", + "lib/net40/Newtonsoft.Json.Schema.dll", + "lib/net40/Newtonsoft.Json.Schema.xml", + "lib/net45/Newtonsoft.Json.Schema.dll", + "lib/net45/Newtonsoft.Json.Schema.xml", + "lib/netstandard2.0/Newtonsoft.Json.Schema.dll", + "lib/netstandard2.0/Newtonsoft.Json.Schema.xml", + "lib/netstandard2.1/Newtonsoft.Json.Schema.dll", + "lib/netstandard2.1/Newtonsoft.Json.Schema.xml", + "newtonsoft.json.schema.4.0.1.nupkg.sha512", + "newtonsoft.json.schema.nuspec", + "packageIcon.png" + ] + }, + "NJsonSchema/11.0.0": { + "sha512": "yJviNfW8U8+ACJO0VyiNuNIDGoRDZO5awNfjL1+6iO7TVI5pfjun+ZBVsv1hLga/IVlhnUPpMj8VuhQAYfXD/A==", + "type": "package", + "path": "njsonschema/11.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "NuGetIcon.png", + "lib/net462/NJsonSchema.dll", + "lib/net462/NJsonSchema.xml", + "lib/net6.0/NJsonSchema.dll", + "lib/net6.0/NJsonSchema.xml", + "lib/netstandard2.0/NJsonSchema.dll", + "lib/netstandard2.0/NJsonSchema.xml", + "njsonschema.11.0.0.nupkg.sha512", + "njsonschema.nuspec" + ] + }, + "NJsonSchema.Annotations/11.0.0": { + "sha512": "kbUrZfspa+Y5Kz0OaRbLQxLtVydWFvkY1CpwfKmravZXG2icphuYHR58EwBZuCQWJb/BL81PGP4FjpDNBFnn6Q==", + "type": "package", + "path": "njsonschema.annotations/11.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "NuGetIcon.png", + "lib/net462/NJsonSchema.Annotations.dll", + "lib/netstandard2.0/NJsonSchema.Annotations.dll", + "njsonschema.annotations.11.0.0.nupkg.sha512", + "njsonschema.annotations.nuspec" + ] + }, + "NJsonSchema.CodeGeneration/11.0.0": { + "sha512": "jnmUXVGYzQ3ss/0mqQ6jx/XxPE/g1d0WojN4Y/h/7yyUY6g7xMK44ntFitcD/Y/FxrETEz1mWYcE8kDMrXUINw==", + "type": "package", + "path": "njsonschema.codegeneration/11.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "NuGetIcon.png", + "lib/net462/NJsonSchema.CodeGeneration.dll", + "lib/net462/NJsonSchema.CodeGeneration.xml", + "lib/netstandard2.0/NJsonSchema.CodeGeneration.dll", + "lib/netstandard2.0/NJsonSchema.CodeGeneration.xml", + "njsonschema.codegeneration.11.0.0.nupkg.sha512", + "njsonschema.codegeneration.nuspec" + ] + }, + "NJsonSchema.CodeGeneration.CSharp/11.0.0": { + "sha512": "Qj1hf2G78fcTouO+ISdUJvjV4VIPE1KqEwedigRY9CeBI9QdHHw7sb72bv4DXnAl3iUXmQcQ0eXYnE8zlZSrhw==", + "type": "package", + "path": "njsonschema.codegeneration.csharp/11.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "NuGetIcon.png", + "lib/net462/NJsonSchema.CodeGeneration.CSharp.dll", + "lib/net462/NJsonSchema.CodeGeneration.CSharp.xml", + "lib/netstandard2.0/NJsonSchema.CodeGeneration.CSharp.dll", + "lib/netstandard2.0/NJsonSchema.CodeGeneration.CSharp.xml", + "njsonschema.codegeneration.csharp.11.0.0.nupkg.sha512", + "njsonschema.codegeneration.csharp.nuspec" + ] + }, + "NJsonSchema.NewtonsoftJson/11.0.0": { + "sha512": "MCugHG7dyQhfwgY1NIaCZNFQzTYwmQpfwm15bksG/Ng1H8up/4DxxH1M9fDtV5xqYBrWGjMRSmTokGr9wwLCPg==", + "type": "package", + "path": "njsonschema.newtonsoftjson/11.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "NuGetIcon.png", + "lib/net462/NJsonSchema.NewtonsoftJson.dll", + "lib/net462/NJsonSchema.NewtonsoftJson.xml", + "lib/netstandard2.0/NJsonSchema.NewtonsoftJson.dll", + "lib/netstandard2.0/NJsonSchema.NewtonsoftJson.xml", + "njsonschema.newtonsoftjson.11.0.0.nupkg.sha512", + "njsonschema.newtonsoftjson.nuspec" + ] + }, + "NJsonSchema.Yaml/11.0.0": { + "sha512": "riCNrkN2YOVYyvvJjtc7zdIYXQT6/l7FMe0XFGH5rfxWN4/Iy/T60+ZzketAIMhzqn65WPmFZ3NUJ1nGtGCrMw==", + "type": "package", + "path": "njsonschema.yaml/11.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "NuGetIcon.png", + "lib/net462/NJsonSchema.Yaml.dll", + "lib/netstandard2.0/NJsonSchema.Yaml.dll", + "njsonschema.yaml.11.0.0.nupkg.sha512", + "njsonschema.yaml.nuspec" + ] + }, + "NLog/5.3.4": { + "sha512": "gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A==", + "type": "package", + "path": "nlog/5.3.4", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "N.png", + "lib/net35/NLog.dll", + "lib/net35/NLog.xml", + "lib/net45/NLog.dll", + "lib/net45/NLog.xml", + "lib/net46/NLog.dll", + "lib/net46/NLog.xml", + "lib/netstandard1.3/NLog.dll", + "lib/netstandard1.3/NLog.xml", + "lib/netstandard1.5/NLog.dll", + "lib/netstandard1.5/NLog.xml", + "lib/netstandard2.0/NLog.dll", + "lib/netstandard2.0/NLog.xml", + "nlog.5.3.4.nupkg.sha512", + "nlog.nuspec" + ] + }, + "NLog.Extensions.Hosting/5.3.8": { + "sha512": "4CyvTI8TzNFh2s8dChxyToyRIK+5famLGI4Q0f0VhKQLxA2R9dcw9+6QPLtDBPCr6zHeXv+3590Ny685xng1DA==", + "type": "package", + "path": "nlog.extensions.hosting/5.3.8", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "N.png", + "README.md", + "lib/net6.0/NLog.Extensions.Hosting.dll", + "lib/net6.0/NLog.Extensions.Hosting.xml", + "lib/net8.0/NLog.Extensions.Hosting.dll", + "lib/net8.0/NLog.Extensions.Hosting.xml", + "lib/netstandard2.0/NLog.Extensions.Hosting.dll", + "lib/netstandard2.0/NLog.Extensions.Hosting.xml", + "lib/netstandard2.1/NLog.Extensions.Hosting.dll", + "lib/netstandard2.1/NLog.Extensions.Hosting.xml", + "nlog.extensions.hosting.5.3.8.nupkg.sha512", + "nlog.extensions.hosting.nuspec" + ] + }, + "NLog.Extensions.Logging/5.3.14": { + "sha512": "ZFcdwdIYcGvWY268QMw2lIqnE8ziJTaS4iLm2ajRMUdgy9MFxJl+Y5s0zQxfgjTxbownGrAkJfoTkquAayKG6A==", + "type": "package", + "path": "nlog.extensions.logging/5.3.14", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "N.png", + "README.md", + "lib/net461/NLog.Extensions.Logging.dll", + "lib/net461/NLog.Extensions.Logging.xml", + "lib/net6.0/NLog.Extensions.Logging.dll", + "lib/net6.0/NLog.Extensions.Logging.xml", + "lib/net8.0/NLog.Extensions.Logging.dll", + "lib/net8.0/NLog.Extensions.Logging.xml", + "lib/netstandard1.3/NLog.Extensions.Logging.dll", + "lib/netstandard1.3/NLog.Extensions.Logging.xml", + "lib/netstandard1.5/NLog.Extensions.Logging.dll", + "lib/netstandard1.5/NLog.Extensions.Logging.xml", + "lib/netstandard2.0/NLog.Extensions.Logging.dll", + "lib/netstandard2.0/NLog.Extensions.Logging.xml", + "lib/netstandard2.1/NLog.Extensions.Logging.dll", + "lib/netstandard2.1/NLog.Extensions.Logging.xml", + "nlog.extensions.logging.5.3.14.nupkg.sha512", + "nlog.extensions.logging.nuspec" + ] + }, + "Npgsql/8.0.5": { + "sha512": "zRG5V8cyeZLpzJlKzFKjEwkRMYIYnHWJvEor2lWXeccS2E1G2nIWYYhnukB51iz5XsWSVEtqg3AxTWM0QJ6vfg==", + "type": "package", + "path": "npgsql/8.0.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net6.0/Npgsql.dll", + "lib/net6.0/Npgsql.xml", + "lib/net7.0/Npgsql.dll", + "lib/net7.0/Npgsql.xml", + "lib/net8.0/Npgsql.dll", + "lib/net8.0/Npgsql.xml", + "lib/netstandard2.0/Npgsql.dll", + "lib/netstandard2.0/Npgsql.xml", + "lib/netstandard2.1/Npgsql.dll", + "lib/netstandard2.1/Npgsql.xml", + "npgsql.8.0.5.nupkg.sha512", + "npgsql.nuspec", + "postgresql.png" + ] + }, + "NSwag.Annotations/14.0.2": { + "sha512": "bAvxk2XMgS8lfaAhZLwzFaR+JJXbrm/hVy8JCNawVu9SIdSMQnZpLIQ1wW3g08CVWISNg57Vg4CfECkeiDD5sQ==", + "type": "package", + "path": "nswag.annotations/14.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "NuGetIcon.png", + "lib/net462/NSwag.Annotations.dll", + "lib/net462/NSwag.Annotations.xml", + "lib/netstandard2.0/NSwag.Annotations.dll", + "lib/netstandard2.0/NSwag.Annotations.xml", + "nswag.annotations.14.0.2.nupkg.sha512", + "nswag.annotations.nuspec" + ] + }, + "NSwag.AspNetCore/14.0.2": { + "sha512": "q6SH/XMpdgNf8ch5JQleHDW/8Tjg8UlWb1LOeUZMK/8l8XXQ9ClBX5uLRPSUYHtUQpGvKtlB+O/pg1KplMK1+w==", + "type": "package", + "path": "nswag.aspnetcore/14.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "NuGetIcon.png", + "build/NSwag.AspNetCore.props", + "build/NSwag.AspNetCore.targets", + "buildMultiTargeting/NSwag.AspNetCore.props", + "buildMultiTargeting/NSwag.AspNetCore.targets", + "lib/net462/NSwag.AspNetCore.dll", + "lib/net462/NSwag.AspNetCore.xml", + "lib/net6.0/NSwag.AspNetCore.dll", + "lib/net6.0/NSwag.AspNetCore.xml", + "lib/net7.0/NSwag.AspNetCore.dll", + "lib/net7.0/NSwag.AspNetCore.xml", + "lib/net8.0/NSwag.AspNetCore.dll", + "lib/net8.0/NSwag.AspNetCore.xml", + "lib/netstandard2.0/NSwag.AspNetCore.dll", + "lib/netstandard2.0/NSwag.AspNetCore.xml", + "nswag.aspnetcore.14.0.2.nupkg.sha512", + "nswag.aspnetcore.nuspec" + ] + }, + "NSwag.CodeGeneration/14.0.2": { + "sha512": "zFOTMY4dQEoCe5lYQZcSw0EfFmeqqd4RkGuYusiyyNReh7b3xSsRoslS70YEtpu+VBPAhXzQWGOdwxxxXya79g==", + "type": "package", + "path": "nswag.codegeneration/14.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "NuGetIcon.png", + "lib/net462/NSwag.CodeGeneration.dll", + "lib/net462/NSwag.CodeGeneration.xml", + "lib/netstandard2.0/NSwag.CodeGeneration.dll", + "lib/netstandard2.0/NSwag.CodeGeneration.xml", + "nswag.codegeneration.14.0.2.nupkg.sha512", + "nswag.codegeneration.nuspec" + ] + }, + "NSwag.CodeGeneration.CSharp/14.0.2": { + "sha512": "tRX21TpF5J/5flV5jZO0PZjuQhPNXBaKfSo5jPkzUiROV+fNZd6mZb8JQVEB2yGhKPkkqYBfnJzjcZ3PTDmdSw==", + "type": "package", + "path": "nswag.codegeneration.csharp/14.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "NuGetIcon.png", + "lib/net462/NSwag.CodeGeneration.CSharp.dll", + "lib/net462/NSwag.CodeGeneration.CSharp.xml", + "lib/netstandard2.0/NSwag.CodeGeneration.CSharp.dll", + "lib/netstandard2.0/NSwag.CodeGeneration.CSharp.xml", + "nswag.codegeneration.csharp.14.0.2.nupkg.sha512", + "nswag.codegeneration.csharp.nuspec" + ] + }, + "NSwag.Core/14.0.2": { + "sha512": "2jjhctHyDVzgRh/c3GRuG78/PS6Vhi+dlouR4X17elGNJ+xwYaiNq8E22LOYiEGa+oIHkIsTk2TTOO0yqSEdHw==", + "type": "package", + "path": "nswag.core/14.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "NuGetIcon.png", + "lib/net462/NSwag.Core.dll", + "lib/net462/NSwag.Core.xml", + "lib/netstandard2.0/NSwag.Core.dll", + "lib/netstandard2.0/NSwag.Core.xml", + "nswag.core.14.0.2.nupkg.sha512", + "nswag.core.nuspec" + ] + }, + "NSwag.Core.Yaml/14.0.2": { + "sha512": "E5FmOkEIgBgzoLrEeHrjO4mQBj00R+pEMXIAzk4rMFUfc//EAy07/HJoj7sqQNWQZJ5HxdDGYdzmtjJtFHfbUQ==", + "type": "package", + "path": "nswag.core.yaml/14.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "NuGetIcon.png", + "lib/net462/NSwag.Core.Yaml.dll", + "lib/netstandard2.0/NSwag.Core.Yaml.dll", + "nswag.core.yaml.14.0.2.nupkg.sha512", + "nswag.core.yaml.nuspec" + ] + }, + "NSwag.Generation/14.0.2": { + "sha512": "vNmPG+aj6w3JbEKJcolcdvAVrMA3HFb9Ndj++cFzYN/42L7WYOXK69TWIjeVXjalZdPo+LLHMOPNjjs6xPK+GQ==", + "type": "package", + "path": "nswag.generation/14.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "NuGetIcon.png", + "lib/net462/NSwag.Generation.dll", + "lib/net462/NSwag.Generation.xml", + "lib/netstandard2.0/NSwag.Generation.dll", + "lib/netstandard2.0/NSwag.Generation.xml", + "nswag.generation.14.0.2.nupkg.sha512", + "nswag.generation.nuspec" + ] + }, + "NSwag.Generation.AspNetCore/14.0.2": { + "sha512": "h0n/xg7WzrmN8CS7ycwEpkNIe9qa7Algf3I0lFjdj75jHjl4lKo2ktuRcKOX2NslKXP9mjgUR2SmXbCZc7EqAg==", + "type": "package", + "path": "nswag.generation.aspnetcore/14.0.2", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "NuGetIcon.png", + "lib/net462/NSwag.Generation.AspNetCore.dll", + "lib/net462/NSwag.Generation.AspNetCore.xml", + "lib/net6.0/NSwag.Generation.AspNetCore.dll", + "lib/net6.0/NSwag.Generation.AspNetCore.xml", + "lib/net7.0/NSwag.Generation.AspNetCore.dll", + "lib/net7.0/NSwag.Generation.AspNetCore.xml", + "lib/net8.0/NSwag.Generation.AspNetCore.dll", + "lib/net8.0/NSwag.Generation.AspNetCore.xml", + "lib/netstandard2.0/NSwag.Generation.AspNetCore.dll", + "lib/netstandard2.0/NSwag.Generation.AspNetCore.xml", + "nswag.generation.aspnetcore.14.0.2.nupkg.sha512", + "nswag.generation.aspnetcore.nuspec" + ] + }, + "NSwag.MSBuild/14.0.2": { + "sha512": "CnW1JgxdO5yKaYV0PxVCMpLv5XC8kN18iH8T1QrKjzTgu8ypNSVUOb+D+kwARiWsjiscebAIjKVvtTYcLS/FSQ==", + "type": "package", + "path": "nswag.msbuild/14.0.2", + "hasTools": true, + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "build/NSwag.MSBuild.props", + "buildCrossTargeting/NSwag.MSBuild.props", + "buildTransitive/NSwag.MSBuild.props", + "nswag.msbuild.14.0.2.nupkg.sha512", + "nswag.msbuild.nuspec", + "tools/Net60/Fluid.dll", + "tools/Net60/Microsoft.AspNetCore.JsonPatch.dll", + "tools/Net60/Microsoft.AspNetCore.Mvc.NewtonsoftJson.dll", + "tools/Net60/Microsoft.AspNetCore.TestHost.dll", + "tools/Net60/Microsoft.Extensions.DependencyModel.dll", + "tools/Net60/Microsoft.Extensions.PlatformAbstractions.dll", + "tools/Net60/NConsole.dll", + "tools/Net60/NJsonSchema.Annotations.dll", + "tools/Net60/NJsonSchema.CodeGeneration.CSharp.dll", + "tools/Net60/NJsonSchema.CodeGeneration.TypeScript.dll", + "tools/Net60/NJsonSchema.CodeGeneration.dll", + "tools/Net60/NJsonSchema.NewtonsoftJson.dll", + "tools/Net60/NJsonSchema.Yaml.dll", + "tools/Net60/NJsonSchema.dll", + "tools/Net60/NSwag.AspNetCore.Launcher.dll", + "tools/Net60/NSwag.AspNetCore.Launcher.exe", + "tools/Net60/NSwag.AspNetCore.Launcher.pdb", + "tools/Net60/NSwag.AspNetCore.Launcher.runtimeconfig.json", + "tools/Net60/NSwag.CodeGeneration.CSharp.dll", + "tools/Net60/NSwag.CodeGeneration.CSharp.pdb", + "tools/Net60/NSwag.CodeGeneration.CSharp.xml", + "tools/Net60/NSwag.CodeGeneration.TypeScript.dll", + "tools/Net60/NSwag.CodeGeneration.TypeScript.pdb", + "tools/Net60/NSwag.CodeGeneration.TypeScript.xml", + "tools/Net60/NSwag.CodeGeneration.dll", + "tools/Net60/NSwag.CodeGeneration.dll.config", + "tools/Net60/NSwag.CodeGeneration.pdb", + "tools/Net60/NSwag.CodeGeneration.xml", + "tools/Net60/NSwag.Commands.dll", + "tools/Net60/NSwag.Commands.pdb", + "tools/Net60/NSwag.Commands.xml", + "tools/Net60/NSwag.Core.Yaml.dll", + "tools/Net60/NSwag.Core.Yaml.pdb", + "tools/Net60/NSwag.Core.dll", + "tools/Net60/NSwag.Core.pdb", + "tools/Net60/NSwag.Core.xml", + "tools/Net60/NSwag.Generation.AspNetCore.dll", + "tools/Net60/NSwag.Generation.AspNetCore.pdb", + "tools/Net60/NSwag.Generation.AspNetCore.xml", + "tools/Net60/NSwag.Generation.dll", + "tools/Net60/NSwag.Generation.pdb", + "tools/Net60/NSwag.Generation.xml", + "tools/Net60/Namotion.Reflection.dll", + "tools/Net60/Newtonsoft.Json.Bson.dll", + "tools/Net60/Newtonsoft.Json.dll", + "tools/Net60/Parlot.dll", + "tools/Net60/TimeZoneConverter.dll", + "tools/Net60/YamlDotNet.dll", + "tools/Net60/dotnet-nswag.deps.json", + "tools/Net60/dotnet-nswag.dll", + "tools/Net60/dotnet-nswag.exe", + "tools/Net60/dotnet-nswag.pdb", + "tools/Net60/dotnet-nswag.runtimeconfig.json", + "tools/Net70/Fluid.dll", + "tools/Net70/Microsoft.AspNetCore.JsonPatch.dll", + "tools/Net70/Microsoft.AspNetCore.Mvc.NewtonsoftJson.dll", + "tools/Net70/Microsoft.AspNetCore.TestHost.dll", + "tools/Net70/Microsoft.Extensions.DependencyModel.dll", + "tools/Net70/Microsoft.Extensions.PlatformAbstractions.dll", + "tools/Net70/NConsole.dll", + "tools/Net70/NJsonSchema.Annotations.dll", + "tools/Net70/NJsonSchema.CodeGeneration.CSharp.dll", + "tools/Net70/NJsonSchema.CodeGeneration.TypeScript.dll", + "tools/Net70/NJsonSchema.CodeGeneration.dll", + "tools/Net70/NJsonSchema.NewtonsoftJson.dll", + "tools/Net70/NJsonSchema.Yaml.dll", + "tools/Net70/NJsonSchema.dll", + "tools/Net70/NSwag.AspNetCore.Launcher.dll", + "tools/Net70/NSwag.AspNetCore.Launcher.exe", + "tools/Net70/NSwag.AspNetCore.Launcher.pdb", + "tools/Net70/NSwag.AspNetCore.Launcher.runtimeconfig.json", + "tools/Net70/NSwag.CodeGeneration.CSharp.dll", + "tools/Net70/NSwag.CodeGeneration.CSharp.pdb", + "tools/Net70/NSwag.CodeGeneration.CSharp.xml", + "tools/Net70/NSwag.CodeGeneration.TypeScript.dll", + "tools/Net70/NSwag.CodeGeneration.TypeScript.pdb", + "tools/Net70/NSwag.CodeGeneration.TypeScript.xml", + "tools/Net70/NSwag.CodeGeneration.dll", + "tools/Net70/NSwag.CodeGeneration.dll.config", + "tools/Net70/NSwag.CodeGeneration.pdb", + "tools/Net70/NSwag.CodeGeneration.xml", + "tools/Net70/NSwag.Commands.dll", + "tools/Net70/NSwag.Commands.pdb", + "tools/Net70/NSwag.Commands.xml", + "tools/Net70/NSwag.Core.Yaml.dll", + "tools/Net70/NSwag.Core.Yaml.pdb", + "tools/Net70/NSwag.Core.dll", + "tools/Net70/NSwag.Core.pdb", + "tools/Net70/NSwag.Core.xml", + "tools/Net70/NSwag.Generation.AspNetCore.dll", + "tools/Net70/NSwag.Generation.AspNetCore.pdb", + "tools/Net70/NSwag.Generation.AspNetCore.xml", + "tools/Net70/NSwag.Generation.dll", + "tools/Net70/NSwag.Generation.pdb", + "tools/Net70/NSwag.Generation.xml", + "tools/Net70/Namotion.Reflection.dll", + "tools/Net70/Newtonsoft.Json.Bson.dll", + "tools/Net70/Newtonsoft.Json.dll", + "tools/Net70/Parlot.dll", + "tools/Net70/TimeZoneConverter.dll", + "tools/Net70/YamlDotNet.dll", + "tools/Net70/dotnet-nswag.deps.json", + "tools/Net70/dotnet-nswag.dll", + "tools/Net70/dotnet-nswag.exe", + "tools/Net70/dotnet-nswag.pdb", + "tools/Net70/dotnet-nswag.runtimeconfig.json", + "tools/Net80/Fluid.dll", + "tools/Net80/Microsoft.AspNetCore.JsonPatch.dll", + "tools/Net80/Microsoft.AspNetCore.Mvc.NewtonsoftJson.dll", + "tools/Net80/Microsoft.AspNetCore.TestHost.dll", + "tools/Net80/Microsoft.Extensions.DependencyModel.dll", + "tools/Net80/Microsoft.Extensions.PlatformAbstractions.dll", + "tools/Net80/NConsole.dll", + "tools/Net80/NJsonSchema.Annotations.dll", + "tools/Net80/NJsonSchema.CodeGeneration.CSharp.dll", + "tools/Net80/NJsonSchema.CodeGeneration.TypeScript.dll", + "tools/Net80/NJsonSchema.CodeGeneration.dll", + "tools/Net80/NJsonSchema.NewtonsoftJson.dll", + "tools/Net80/NJsonSchema.Yaml.dll", + "tools/Net80/NJsonSchema.dll", + "tools/Net80/NSwag.AspNetCore.Launcher.dll", + "tools/Net80/NSwag.AspNetCore.Launcher.exe", + "tools/Net80/NSwag.AspNetCore.Launcher.pdb", + "tools/Net80/NSwag.AspNetCore.Launcher.runtimeconfig.json", + "tools/Net80/NSwag.CodeGeneration.CSharp.dll", + "tools/Net80/NSwag.CodeGeneration.CSharp.pdb", + "tools/Net80/NSwag.CodeGeneration.CSharp.xml", + "tools/Net80/NSwag.CodeGeneration.TypeScript.dll", + "tools/Net80/NSwag.CodeGeneration.TypeScript.pdb", + "tools/Net80/NSwag.CodeGeneration.TypeScript.xml", + "tools/Net80/NSwag.CodeGeneration.dll", + "tools/Net80/NSwag.CodeGeneration.dll.config", + "tools/Net80/NSwag.CodeGeneration.pdb", + "tools/Net80/NSwag.CodeGeneration.xml", + "tools/Net80/NSwag.Commands.dll", + "tools/Net80/NSwag.Commands.pdb", + "tools/Net80/NSwag.Commands.xml", + "tools/Net80/NSwag.Core.Yaml.dll", + "tools/Net80/NSwag.Core.Yaml.pdb", + "tools/Net80/NSwag.Core.dll", + "tools/Net80/NSwag.Core.pdb", + "tools/Net80/NSwag.Core.xml", + "tools/Net80/NSwag.Generation.AspNetCore.dll", + "tools/Net80/NSwag.Generation.AspNetCore.pdb", + "tools/Net80/NSwag.Generation.AspNetCore.xml", + "tools/Net80/NSwag.Generation.dll", + "tools/Net80/NSwag.Generation.pdb", + "tools/Net80/NSwag.Generation.xml", + "tools/Net80/Namotion.Reflection.dll", + "tools/Net80/Newtonsoft.Json.Bson.dll", + "tools/Net80/Newtonsoft.Json.dll", + "tools/Net80/Parlot.dll", + "tools/Net80/TimeZoneConverter.dll", + "tools/Net80/YamlDotNet.dll", + "tools/Net80/dotnet-nswag.deps.json", + "tools/Net80/dotnet-nswag.dll", + "tools/Net80/dotnet-nswag.exe", + "tools/Net80/dotnet-nswag.pdb", + "tools/Net80/dotnet-nswag.runtimeconfig.json", + "tools/Win/Fluid.dll", + "tools/Win/Microsoft.AspNetCore.Authentication.Abstractions.dll", + "tools/Win/Microsoft.AspNetCore.Authentication.Core.dll", + "tools/Win/Microsoft.AspNetCore.Authorization.Policy.dll", + "tools/Win/Microsoft.AspNetCore.Authorization.dll", + "tools/Win/Microsoft.AspNetCore.Connections.Abstractions.dll", + "tools/Win/Microsoft.AspNetCore.Diagnostics.Abstractions.dll", + "tools/Win/Microsoft.AspNetCore.Diagnostics.dll", + "tools/Win/Microsoft.AspNetCore.HostFiltering.dll", + "tools/Win/Microsoft.AspNetCore.Hosting.Abstractions.dll", + "tools/Win/Microsoft.AspNetCore.Hosting.Server.Abstractions.dll", + "tools/Win/Microsoft.AspNetCore.Hosting.dll", + "tools/Win/Microsoft.AspNetCore.Http.Abstractions.dll", + "tools/Win/Microsoft.AspNetCore.Http.Extensions.dll", + "tools/Win/Microsoft.AspNetCore.Http.Features.dll", + "tools/Win/Microsoft.AspNetCore.Http.dll", + "tools/Win/Microsoft.AspNetCore.HttpOverrides.dll", + "tools/Win/Microsoft.AspNetCore.JsonPatch.dll", + "tools/Win/Microsoft.AspNetCore.Mvc.Abstractions.dll", + "tools/Win/Microsoft.AspNetCore.Mvc.ApiExplorer.dll", + "tools/Win/Microsoft.AspNetCore.Mvc.Core.dll", + "tools/Win/Microsoft.AspNetCore.Mvc.Formatters.Json.dll", + "tools/Win/Microsoft.AspNetCore.ResponseCaching.Abstractions.dll", + "tools/Win/Microsoft.AspNetCore.Routing.Abstractions.dll", + "tools/Win/Microsoft.AspNetCore.Routing.dll", + "tools/Win/Microsoft.AspNetCore.Server.IISIntegration.dll", + "tools/Win/Microsoft.AspNetCore.Server.Kestrel.Core.dll", + "tools/Win/Microsoft.AspNetCore.Server.Kestrel.Https.dll", + "tools/Win/Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.dll", + "tools/Win/Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.dll", + "tools/Win/Microsoft.AspNetCore.Server.Kestrel.dll", + "tools/Win/Microsoft.AspNetCore.TestHost.dll", + "tools/Win/Microsoft.AspNetCore.WebUtilities.dll", + "tools/Win/Microsoft.AspNetCore.dll", + "tools/Win/Microsoft.Bcl.AsyncInterfaces.dll", + "tools/Win/Microsoft.DotNet.PlatformAbstractions.dll", + "tools/Win/Microsoft.Extensions.Configuration.Abstractions.dll", + "tools/Win/Microsoft.Extensions.Configuration.Binder.dll", + "tools/Win/Microsoft.Extensions.Configuration.CommandLine.dll", + "tools/Win/Microsoft.Extensions.Configuration.EnvironmentVariables.dll", + "tools/Win/Microsoft.Extensions.Configuration.FileExtensions.dll", + "tools/Win/Microsoft.Extensions.Configuration.Json.dll", + "tools/Win/Microsoft.Extensions.Configuration.UserSecrets.dll", + "tools/Win/Microsoft.Extensions.Configuration.dll", + "tools/Win/Microsoft.Extensions.DependencyInjection.Abstractions.dll", + "tools/Win/Microsoft.Extensions.DependencyInjection.dll", + "tools/Win/Microsoft.Extensions.DependencyModel.dll", + "tools/Win/Microsoft.Extensions.FileProviders.Abstractions.dll", + "tools/Win/Microsoft.Extensions.FileProviders.Physical.dll", + "tools/Win/Microsoft.Extensions.FileSystemGlobbing.dll", + "tools/Win/Microsoft.Extensions.Hosting.Abstractions.dll", + "tools/Win/Microsoft.Extensions.Logging.Abstractions.dll", + "tools/Win/Microsoft.Extensions.Logging.Configuration.dll", + "tools/Win/Microsoft.Extensions.Logging.Console.dll", + "tools/Win/Microsoft.Extensions.Logging.Debug.dll", + "tools/Win/Microsoft.Extensions.Logging.dll", + "tools/Win/Microsoft.Extensions.ObjectPool.dll", + "tools/Win/Microsoft.Extensions.Options.ConfigurationExtensions.dll", + "tools/Win/Microsoft.Extensions.Options.dll", + "tools/Win/Microsoft.Extensions.PlatformAbstractions.dll", + "tools/Win/Microsoft.Extensions.Primitives.dll", + "tools/Win/Microsoft.Net.Http.Headers.dll", + "tools/Win/Microsoft.Win32.Primitives.dll", + "tools/Win/NConsole.dll", + "tools/Win/NJsonSchema.Annotations.dll", + "tools/Win/NJsonSchema.CodeGeneration.CSharp.dll", + "tools/Win/NJsonSchema.CodeGeneration.TypeScript.dll", + "tools/Win/NJsonSchema.CodeGeneration.dll", + "tools/Win/NJsonSchema.NewtonsoftJson.dll", + "tools/Win/NJsonSchema.Yaml.dll", + "tools/Win/NJsonSchema.dll", + "tools/Win/NSwag.AspNetCore.Launcher.exe", + "tools/Win/NSwag.AspNetCore.Launcher.exe.config", + "tools/Win/NSwag.AspNetCore.Launcher.pdb", + "tools/Win/NSwag.AspNetCore.Launcher.x86.exe", + "tools/Win/NSwag.AspNetCore.Launcher.x86.exe.config", + "tools/Win/NSwag.CodeGeneration.CSharp.dll", + "tools/Win/NSwag.CodeGeneration.CSharp.pdb", + "tools/Win/NSwag.CodeGeneration.CSharp.xml", + "tools/Win/NSwag.CodeGeneration.TypeScript.dll", + "tools/Win/NSwag.CodeGeneration.TypeScript.pdb", + "tools/Win/NSwag.CodeGeneration.TypeScript.xml", + "tools/Win/NSwag.CodeGeneration.dll", + "tools/Win/NSwag.CodeGeneration.dll.config", + "tools/Win/NSwag.CodeGeneration.pdb", + "tools/Win/NSwag.CodeGeneration.xml", + "tools/Win/NSwag.Commands.dll", + "tools/Win/NSwag.Commands.pdb", + "tools/Win/NSwag.Commands.xml", + "tools/Win/NSwag.Core.Yaml.dll", + "tools/Win/NSwag.Core.Yaml.pdb", + "tools/Win/NSwag.Core.dll", + "tools/Win/NSwag.Core.pdb", + "tools/Win/NSwag.Core.xml", + "tools/Win/NSwag.Generation.AspNetCore.dll", + "tools/Win/NSwag.Generation.AspNetCore.pdb", + "tools/Win/NSwag.Generation.AspNetCore.xml", + "tools/Win/NSwag.Generation.dll", + "tools/Win/NSwag.Generation.pdb", + "tools/Win/NSwag.Generation.xml", + "tools/Win/NSwag.exe", + "tools/Win/NSwag.exe.config", + "tools/Win/NSwag.pdb", + "tools/Win/NSwag.x86.exe", + "tools/Win/NSwag.x86.exe.config", + "tools/Win/Namotion.Reflection.dll", + "tools/Win/Newtonsoft.Json.dll", + "tools/Win/Parlot.dll", + "tools/Win/System.AppContext.dll", + "tools/Win/System.Buffers.dll", + "tools/Win/System.Collections.Concurrent.dll", + "tools/Win/System.Collections.Immutable.dll", + "tools/Win/System.Collections.NonGeneric.dll", + "tools/Win/System.Collections.Specialized.dll", + "tools/Win/System.Collections.dll", + "tools/Win/System.ComponentModel.EventBasedAsync.dll", + "tools/Win/System.ComponentModel.Primitives.dll", + "tools/Win/System.ComponentModel.TypeConverter.dll", + "tools/Win/System.ComponentModel.dll", + "tools/Win/System.Console.dll", + "tools/Win/System.Data.Common.dll", + "tools/Win/System.Diagnostics.Contracts.dll", + "tools/Win/System.Diagnostics.Debug.dll", + "tools/Win/System.Diagnostics.DiagnosticSource.dll", + "tools/Win/System.Diagnostics.FileVersionInfo.dll", + "tools/Win/System.Diagnostics.Process.dll", + "tools/Win/System.Diagnostics.StackTrace.dll", + "tools/Win/System.Diagnostics.TextWriterTraceListener.dll", + "tools/Win/System.Diagnostics.Tools.dll", + "tools/Win/System.Diagnostics.TraceSource.dll", + "tools/Win/System.Diagnostics.Tracing.dll", + "tools/Win/System.Drawing.Primitives.dll", + "tools/Win/System.Dynamic.Runtime.dll", + "tools/Win/System.Globalization.Calendars.dll", + "tools/Win/System.Globalization.Extensions.dll", + "tools/Win/System.Globalization.dll", + "tools/Win/System.IO.Compression.ZipFile.dll", + "tools/Win/System.IO.Compression.dll", + "tools/Win/System.IO.FileSystem.DriveInfo.dll", + "tools/Win/System.IO.FileSystem.Primitives.dll", + "tools/Win/System.IO.FileSystem.Watcher.dll", + "tools/Win/System.IO.FileSystem.dll", + "tools/Win/System.IO.IsolatedStorage.dll", + "tools/Win/System.IO.MemoryMappedFiles.dll", + "tools/Win/System.IO.Pipelines.dll", + "tools/Win/System.IO.Pipes.dll", + "tools/Win/System.IO.UnmanagedMemoryStream.dll", + "tools/Win/System.IO.dll", + "tools/Win/System.Linq.Expressions.dll", + "tools/Win/System.Linq.Parallel.dll", + "tools/Win/System.Linq.Queryable.dll", + "tools/Win/System.Linq.dll", + "tools/Win/System.Memory.dll", + "tools/Win/System.Net.Http.dll", + "tools/Win/System.Net.NameResolution.dll", + "tools/Win/System.Net.NetworkInformation.dll", + "tools/Win/System.Net.Ping.dll", + "tools/Win/System.Net.Primitives.dll", + "tools/Win/System.Net.Requests.dll", + "tools/Win/System.Net.Security.dll", + "tools/Win/System.Net.Sockets.dll", + "tools/Win/System.Net.WebHeaderCollection.dll", + "tools/Win/System.Net.WebSockets.Client.dll", + "tools/Win/System.Net.WebSockets.dll", + "tools/Win/System.Numerics.Vectors.dll", + "tools/Win/System.ObjectModel.dll", + "tools/Win/System.Reflection.Extensions.dll", + "tools/Win/System.Reflection.Metadata.dll", + "tools/Win/System.Reflection.Primitives.dll", + "tools/Win/System.Reflection.dll", + "tools/Win/System.Resources.Reader.dll", + "tools/Win/System.Resources.ResourceManager.dll", + "tools/Win/System.Resources.Writer.dll", + "tools/Win/System.Runtime.CompilerServices.Unsafe.dll", + "tools/Win/System.Runtime.CompilerServices.VisualC.dll", + "tools/Win/System.Runtime.Extensions.dll", + "tools/Win/System.Runtime.Handles.dll", + "tools/Win/System.Runtime.InteropServices.RuntimeInformation.dll", + "tools/Win/System.Runtime.InteropServices.dll", + "tools/Win/System.Runtime.Numerics.dll", + "tools/Win/System.Runtime.Serialization.Formatters.dll", + "tools/Win/System.Runtime.Serialization.Json.dll", + "tools/Win/System.Runtime.Serialization.Primitives.dll", + "tools/Win/System.Runtime.Serialization.Xml.dll", + "tools/Win/System.Runtime.dll", + "tools/Win/System.Security.Claims.dll", + "tools/Win/System.Security.Cryptography.Algorithms.dll", + "tools/Win/System.Security.Cryptography.Cng.dll", + "tools/Win/System.Security.Cryptography.Csp.dll", + "tools/Win/System.Security.Cryptography.Encoding.dll", + "tools/Win/System.Security.Cryptography.Primitives.dll", + "tools/Win/System.Security.Cryptography.X509Certificates.dll", + "tools/Win/System.Security.Principal.Windows.dll", + "tools/Win/System.Security.Principal.dll", + "tools/Win/System.Security.SecureString.dll", + "tools/Win/System.Text.Encoding.Extensions.dll", + "tools/Win/System.Text.Encoding.dll", + "tools/Win/System.Text.Encodings.Web.dll", + "tools/Win/System.Text.Json.dll", + "tools/Win/System.Text.RegularExpressions.dll", + "tools/Win/System.Threading.Overlapped.dll", + "tools/Win/System.Threading.Tasks.Extensions.dll", + "tools/Win/System.Threading.Tasks.Parallel.dll", + "tools/Win/System.Threading.Tasks.dll", + "tools/Win/System.Threading.Thread.dll", + "tools/Win/System.Threading.ThreadPool.dll", + "tools/Win/System.Threading.Timer.dll", + "tools/Win/System.Threading.dll", + "tools/Win/System.ValueTuple.dll", + "tools/Win/System.Xml.ReaderWriter.dll", + "tools/Win/System.Xml.XDocument.dll", + "tools/Win/System.Xml.XPath.XDocument.dll", + "tools/Win/System.Xml.XPath.dll", + "tools/Win/System.Xml.XmlDocument.dll", + "tools/Win/System.Xml.XmlSerializer.dll", + "tools/Win/TimeZoneConverter.dll", + "tools/Win/YamlDotNet.dll", + "tools/Win/netstandard.dll" + ] + }, + "Parlot/0.0.24": { + "sha512": "jdhTa3NK1Vy8CdiWitfIPfQfmg9KvEdrVSYU6wquPQxF4FfGGtuTZyeduUDWDwU51ql6X9o/mDpHqHQQUy5k6w==", + "type": "package", + "path": "parlot/0.0.24", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Parlot.dll", + "lib/netstandard2.0/Parlot.xml", + "lib/netstandard2.1/Parlot.dll", + "lib/netstandard2.1/Parlot.xml", + "parlot.0.0.24.nupkg.sha512", + "parlot.nuspec" + ] + }, + "Polly/8.3.1": { + "sha512": "xN9AxOudus8u4a//Tfu6Wxd5Oj7S4pjh/651S6FfIiVrbxQ8TeM+ieZC8c0y7Qto70zKBM5g8rBTqbAJnbetOA==", + "type": "package", + "path": "polly/8.3.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/Polly.dll", + "lib/net462/Polly.pdb", + "lib/net462/Polly.xml", + "lib/net472/Polly.dll", + "lib/net472/Polly.pdb", + "lib/net472/Polly.xml", + "lib/net6.0/Polly.dll", + "lib/net6.0/Polly.pdb", + "lib/net6.0/Polly.xml", + "lib/netstandard2.0/Polly.dll", + "lib/netstandard2.0/Polly.pdb", + "lib/netstandard2.0/Polly.xml", + "package-icon.png", + "package-readme.md", + "polly.8.3.1.nupkg.sha512", + "polly.nuspec" + ] + }, + "Polly.Core/8.3.1": { + "sha512": "b9mMAjqXuCXFCtf/RtRPwFUkAm/sz37s7G+taDvS5EqfkJsLiWfO2xO2cSISjIgIY+88oIZTGguP6UrRGRlqzg==", + "type": "package", + "path": "polly.core/8.3.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/Polly.Core.dll", + "lib/net462/Polly.Core.pdb", + "lib/net462/Polly.Core.xml", + "lib/net472/Polly.Core.dll", + "lib/net472/Polly.Core.pdb", + "lib/net472/Polly.Core.xml", + "lib/net6.0/Polly.Core.dll", + "lib/net6.0/Polly.Core.pdb", + "lib/net6.0/Polly.Core.xml", + "lib/net8.0/Polly.Core.dll", + "lib/net8.0/Polly.Core.pdb", + "lib/net8.0/Polly.Core.xml", + "lib/netstandard2.0/Polly.Core.dll", + "lib/netstandard2.0/Polly.Core.pdb", + "lib/netstandard2.0/Polly.Core.xml", + "package-icon.png", + "package-readme.md", + "polly.core.8.3.1.nupkg.sha512", + "polly.core.nuspec" + ] + }, + "Portable.BouncyCastle/1.9.0": { + "sha512": "eZZBCABzVOek+id9Xy04HhmgykF0wZg9wpByzrWN7q8qEI0Qen9b7tfd7w8VA3dOeesumMG7C5ZPy0jk7PSRHw==", + "type": "package", + "path": "portable.bouncycastle/1.9.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net40/BouncyCastle.Crypto.dll", + "lib/net40/BouncyCastle.Crypto.xml", + "lib/netstandard2.0/BouncyCastle.Crypto.dll", + "lib/netstandard2.0/BouncyCastle.Crypto.xml", + "portable.bouncycastle.1.9.0.nupkg.sha512", + "portable.bouncycastle.nuspec" + ] + }, + "prometheus-net/8.2.0": { + "sha512": "pLsOu9HbJKJWeyg6IAb57K/JeJa+Ti1uD47c2+SANjga6UuDyeZN/if+9Q2H+s96x8/8DDT8AJ/9UU4+GsK/NA==", + "type": "package", + "path": "prometheus-net/8.2.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net462/Prometheus.NetStandard.dll", + "lib/net462/Prometheus.NetStandard.xml", + "lib/net6.0/Prometheus.NetStandard.dll", + "lib/net6.0/Prometheus.NetStandard.xml", + "lib/net7.0/Prometheus.NetStandard.dll", + "lib/net7.0/Prometheus.NetStandard.xml", + "lib/netstandard2.0/Prometheus.NetStandard.dll", + "lib/netstandard2.0/Prometheus.NetStandard.xml", + "prometheus-net-logo.png", + "prometheus-net.8.2.0.nupkg.sha512", + "prometheus-net.nuspec" + ] + }, + "prometheus-net.AspNetCore/8.1.0": { + "sha512": "6M63K2a0mgUpT24di72I3LebCzY4V5uIaFDdsJpg+OLJdoLuhGqdKAdHPoWSQN9QnDxxAKuuEGYjNdIAFGk8ug==", + "type": "package", + "path": "prometheus-net.aspnetcore/8.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net6.0/Prometheus.AspNetCore.dll", + "lib/net6.0/Prometheus.AspNetCore.xml", + "prometheus-net-logo.png", + "prometheus-net.aspnetcore.8.1.0.nupkg.sha512", + "prometheus-net.aspnetcore.nuspec" + ] + }, + "protobuf-net/3.2.30": { + "sha512": "C/UTlmxEJHAHpqm8xQK1UyJKaIynVCSNG4mVrbLgnZ7ccH28nN49O8iMJvKEodTgVbnimvy+3mIiAdW6mATwnw==", + "type": "package", + "path": "protobuf-net/3.2.30", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.dll", + "lib/net462/protobuf-net.xml", + "lib/net6.0/protobuf-net.dll", + "lib/net6.0/protobuf-net.xml", + "lib/netstandard2.0/protobuf-net.dll", + "lib/netstandard2.0/protobuf-net.xml", + "lib/netstandard2.1/protobuf-net.dll", + "lib/netstandard2.1/protobuf-net.xml", + "protobuf-net.3.2.30.nupkg.sha512", + "protobuf-net.nuspec", + "protobuf-net.png" + ] + }, + "protobuf-net.Core/3.2.30": { + "sha512": "v2ZxxYrz+X212ukSx+uqkLuPu414bvmSAnTyf+PBUKR9ENJxO4P/csorA/27456MCp1JNoMssDj/f91RDiwBfQ==", + "type": "package", + "path": "protobuf-net.core/3.2.30", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.Core.dll", + "lib/net462/protobuf-net.Core.xml", + "lib/net6.0/protobuf-net.Core.dll", + "lib/net6.0/protobuf-net.Core.xml", + "lib/netstandard2.0/protobuf-net.Core.dll", + "lib/netstandard2.0/protobuf-net.Core.xml", + "lib/netstandard2.1/protobuf-net.Core.dll", + "lib/netstandard2.1/protobuf-net.Core.xml", + "protobuf-net.core.3.2.30.nupkg.sha512", + "protobuf-net.core.nuspec", + "protobuf-net.png" + ] + }, + "runtime.native.System/4.3.0": { + "sha512": "c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==", + "type": "package", + "path": "runtime.native.system/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/netstandard1.0/_._", + "runtime.native.system.4.3.0.nupkg.sha512", + "runtime.native.system.nuspec" + ] + }, + "System.Collections/4.3.0": { + "sha512": "3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", + "type": "package", + "path": "system.collections/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/portable-net45+win8+wp8+wpa81/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/System.Collections.dll", + "ref/netcore50/System.Collections.xml", + "ref/netcore50/de/System.Collections.xml", + "ref/netcore50/es/System.Collections.xml", + "ref/netcore50/fr/System.Collections.xml", + "ref/netcore50/it/System.Collections.xml", + "ref/netcore50/ja/System.Collections.xml", + "ref/netcore50/ko/System.Collections.xml", + "ref/netcore50/ru/System.Collections.xml", + "ref/netcore50/zh-hans/System.Collections.xml", + "ref/netcore50/zh-hant/System.Collections.xml", + "ref/netstandard1.0/System.Collections.dll", + "ref/netstandard1.0/System.Collections.xml", + "ref/netstandard1.0/de/System.Collections.xml", + "ref/netstandard1.0/es/System.Collections.xml", + "ref/netstandard1.0/fr/System.Collections.xml", + "ref/netstandard1.0/it/System.Collections.xml", + "ref/netstandard1.0/ja/System.Collections.xml", + "ref/netstandard1.0/ko/System.Collections.xml", + "ref/netstandard1.0/ru/System.Collections.xml", + "ref/netstandard1.0/zh-hans/System.Collections.xml", + "ref/netstandard1.0/zh-hant/System.Collections.xml", + "ref/netstandard1.3/System.Collections.dll", + "ref/netstandard1.3/System.Collections.xml", + "ref/netstandard1.3/de/System.Collections.xml", + "ref/netstandard1.3/es/System.Collections.xml", + "ref/netstandard1.3/fr/System.Collections.xml", + "ref/netstandard1.3/it/System.Collections.xml", + "ref/netstandard1.3/ja/System.Collections.xml", + "ref/netstandard1.3/ko/System.Collections.xml", + "ref/netstandard1.3/ru/System.Collections.xml", + "ref/netstandard1.3/zh-hans/System.Collections.xml", + "ref/netstandard1.3/zh-hant/System.Collections.xml", + "ref/portable-net45+win8+wp8+wpa81/_._", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.collections.4.3.0.nupkg.sha512", + "system.collections.nuspec" + ] + }, + "System.Collections.Immutable/7.0.0": { + "sha512": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "type": "package", + "path": "system.collections.immutable/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "README.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Collections.Immutable.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Collections.Immutable.targets", + "lib/net462/System.Collections.Immutable.dll", + "lib/net462/System.Collections.Immutable.xml", + "lib/net6.0/System.Collections.Immutable.dll", + "lib/net6.0/System.Collections.Immutable.xml", + "lib/net7.0/System.Collections.Immutable.dll", + "lib/net7.0/System.Collections.Immutable.xml", + "lib/netstandard2.0/System.Collections.Immutable.dll", + "lib/netstandard2.0/System.Collections.Immutable.xml", + "system.collections.immutable.7.0.0.nupkg.sha512", + "system.collections.immutable.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.ComponentModel.Annotations/5.0.0": { + "sha512": "dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg==", + "type": "package", + "path": "system.componentmodel.annotations/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/net461/System.ComponentModel.Annotations.dll", + "lib/netcore50/System.ComponentModel.Annotations.dll", + "lib/netstandard1.4/System.ComponentModel.Annotations.dll", + "lib/netstandard2.0/System.ComponentModel.Annotations.dll", + "lib/netstandard2.1/System.ComponentModel.Annotations.dll", + "lib/netstandard2.1/System.ComponentModel.Annotations.xml", + "lib/portable-net45+win8/_._", + "lib/win8/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/net461/System.ComponentModel.Annotations.dll", + "ref/net461/System.ComponentModel.Annotations.xml", + "ref/netcore50/System.ComponentModel.Annotations.dll", + "ref/netcore50/System.ComponentModel.Annotations.xml", + "ref/netcore50/de/System.ComponentModel.Annotations.xml", + "ref/netcore50/es/System.ComponentModel.Annotations.xml", + "ref/netcore50/fr/System.ComponentModel.Annotations.xml", + "ref/netcore50/it/System.ComponentModel.Annotations.xml", + "ref/netcore50/ja/System.ComponentModel.Annotations.xml", + "ref/netcore50/ko/System.ComponentModel.Annotations.xml", + "ref/netcore50/ru/System.ComponentModel.Annotations.xml", + "ref/netcore50/zh-hans/System.ComponentModel.Annotations.xml", + "ref/netcore50/zh-hant/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/System.ComponentModel.Annotations.dll", + "ref/netstandard1.1/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/de/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/es/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/fr/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/it/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/ja/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/ko/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/ru/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/zh-hans/System.ComponentModel.Annotations.xml", + "ref/netstandard1.1/zh-hant/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/System.ComponentModel.Annotations.dll", + "ref/netstandard1.3/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/de/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/es/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/fr/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/it/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/ja/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/ko/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/ru/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/zh-hans/System.ComponentModel.Annotations.xml", + "ref/netstandard1.3/zh-hant/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/System.ComponentModel.Annotations.dll", + "ref/netstandard1.4/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/de/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/es/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/fr/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/it/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/ja/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/ko/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/ru/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/zh-hans/System.ComponentModel.Annotations.xml", + "ref/netstandard1.4/zh-hant/System.ComponentModel.Annotations.xml", + "ref/netstandard2.0/System.ComponentModel.Annotations.dll", + "ref/netstandard2.0/System.ComponentModel.Annotations.xml", + "ref/netstandard2.1/System.ComponentModel.Annotations.dll", + "ref/netstandard2.1/System.ComponentModel.Annotations.xml", + "ref/portable-net45+win8/_._", + "ref/win8/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.componentmodel.annotations.5.0.0.nupkg.sha512", + "system.componentmodel.annotations.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Diagnostics.Debug/4.3.0": { + "sha512": "ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==", + "type": "package", + "path": "system.diagnostics.debug/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/portable-net45+win8+wp8+wpa81/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/System.Diagnostics.Debug.dll", + "ref/netcore50/System.Diagnostics.Debug.xml", + "ref/netcore50/de/System.Diagnostics.Debug.xml", + "ref/netcore50/es/System.Diagnostics.Debug.xml", + "ref/netcore50/fr/System.Diagnostics.Debug.xml", + "ref/netcore50/it/System.Diagnostics.Debug.xml", + "ref/netcore50/ja/System.Diagnostics.Debug.xml", + "ref/netcore50/ko/System.Diagnostics.Debug.xml", + "ref/netcore50/ru/System.Diagnostics.Debug.xml", + "ref/netcore50/zh-hans/System.Diagnostics.Debug.xml", + "ref/netcore50/zh-hant/System.Diagnostics.Debug.xml", + "ref/netstandard1.0/System.Diagnostics.Debug.dll", + "ref/netstandard1.0/System.Diagnostics.Debug.xml", + "ref/netstandard1.0/de/System.Diagnostics.Debug.xml", + "ref/netstandard1.0/es/System.Diagnostics.Debug.xml", + "ref/netstandard1.0/fr/System.Diagnostics.Debug.xml", + "ref/netstandard1.0/it/System.Diagnostics.Debug.xml", + "ref/netstandard1.0/ja/System.Diagnostics.Debug.xml", + "ref/netstandard1.0/ko/System.Diagnostics.Debug.xml", + "ref/netstandard1.0/ru/System.Diagnostics.Debug.xml", + "ref/netstandard1.0/zh-hans/System.Diagnostics.Debug.xml", + "ref/netstandard1.0/zh-hant/System.Diagnostics.Debug.xml", + "ref/netstandard1.3/System.Diagnostics.Debug.dll", + "ref/netstandard1.3/System.Diagnostics.Debug.xml", + "ref/netstandard1.3/de/System.Diagnostics.Debug.xml", + "ref/netstandard1.3/es/System.Diagnostics.Debug.xml", + "ref/netstandard1.3/fr/System.Diagnostics.Debug.xml", + "ref/netstandard1.3/it/System.Diagnostics.Debug.xml", + "ref/netstandard1.3/ja/System.Diagnostics.Debug.xml", + "ref/netstandard1.3/ko/System.Diagnostics.Debug.xml", + "ref/netstandard1.3/ru/System.Diagnostics.Debug.xml", + "ref/netstandard1.3/zh-hans/System.Diagnostics.Debug.xml", + "ref/netstandard1.3/zh-hant/System.Diagnostics.Debug.xml", + "ref/portable-net45+win8+wp8+wpa81/_._", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.diagnostics.debug.4.3.0.nupkg.sha512", + "system.diagnostics.debug.nuspec" + ] + }, + "System.Diagnostics.DiagnosticSource/8.0.1": { + "sha512": "vaoWjvkG1aenR2XdjaVivlCV9fADfgyhW5bZtXT23qaEea0lWiUljdQuze4E31vKM7ZWJaSUsbYIKE3rnzfZUg==", + "type": "package", + "path": "system.diagnostics.diagnosticsource/8.0.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Diagnostics.DiagnosticSource.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Diagnostics.DiagnosticSource.targets", + "lib/net462/System.Diagnostics.DiagnosticSource.dll", + "lib/net462/System.Diagnostics.DiagnosticSource.xml", + "lib/net6.0/System.Diagnostics.DiagnosticSource.dll", + "lib/net6.0/System.Diagnostics.DiagnosticSource.xml", + "lib/net7.0/System.Diagnostics.DiagnosticSource.dll", + "lib/net7.0/System.Diagnostics.DiagnosticSource.xml", + "lib/net8.0/System.Diagnostics.DiagnosticSource.dll", + "lib/net8.0/System.Diagnostics.DiagnosticSource.xml", + "lib/netstandard2.0/System.Diagnostics.DiagnosticSource.dll", + "lib/netstandard2.0/System.Diagnostics.DiagnosticSource.xml", + "system.diagnostics.diagnosticsource.8.0.1.nupkg.sha512", + "system.diagnostics.diagnosticsource.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Diagnostics.Process/4.3.0": { + "sha512": "J0wOX07+QASQblsfxmIMFc9Iq7KTXYL3zs2G/Xc704Ylv3NpuVdo6gij6V3PGiptTxqsK0K7CdXenRvKUnkA2g==", + "type": "package", + "path": "system.diagnostics.process/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Diagnostics.Process.dll", + "lib/net461/System.Diagnostics.Process.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Diagnostics.Process.dll", + "ref/net461/System.Diagnostics.Process.dll", + "ref/netstandard1.3/System.Diagnostics.Process.dll", + "ref/netstandard1.3/System.Diagnostics.Process.xml", + "ref/netstandard1.3/de/System.Diagnostics.Process.xml", + "ref/netstandard1.3/es/System.Diagnostics.Process.xml", + "ref/netstandard1.3/fr/System.Diagnostics.Process.xml", + "ref/netstandard1.3/it/System.Diagnostics.Process.xml", + "ref/netstandard1.3/ja/System.Diagnostics.Process.xml", + "ref/netstandard1.3/ko/System.Diagnostics.Process.xml", + "ref/netstandard1.3/ru/System.Diagnostics.Process.xml", + "ref/netstandard1.3/zh-hans/System.Diagnostics.Process.xml", + "ref/netstandard1.3/zh-hant/System.Diagnostics.Process.xml", + "ref/netstandard1.4/System.Diagnostics.Process.dll", + "ref/netstandard1.4/System.Diagnostics.Process.xml", + "ref/netstandard1.4/de/System.Diagnostics.Process.xml", + "ref/netstandard1.4/es/System.Diagnostics.Process.xml", + "ref/netstandard1.4/fr/System.Diagnostics.Process.xml", + "ref/netstandard1.4/it/System.Diagnostics.Process.xml", + "ref/netstandard1.4/ja/System.Diagnostics.Process.xml", + "ref/netstandard1.4/ko/System.Diagnostics.Process.xml", + "ref/netstandard1.4/ru/System.Diagnostics.Process.xml", + "ref/netstandard1.4/zh-hans/System.Diagnostics.Process.xml", + "ref/netstandard1.4/zh-hant/System.Diagnostics.Process.xml", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "runtimes/linux/lib/netstandard1.4/System.Diagnostics.Process.dll", + "runtimes/osx/lib/netstandard1.4/System.Diagnostics.Process.dll", + "runtimes/win/lib/net46/System.Diagnostics.Process.dll", + "runtimes/win/lib/net461/System.Diagnostics.Process.dll", + "runtimes/win/lib/netstandard1.4/System.Diagnostics.Process.dll", + "runtimes/win7/lib/netcore50/_._", + "system.diagnostics.process.4.3.0.nupkg.sha512", + "system.diagnostics.process.nuspec" + ] + }, + "System.Formats.Asn1/6.0.0": { + "sha512": "T6fD00dQ3NTbPDy31m4eQUwKW84s03z0N2C8HpOklyeaDgaJPa/TexP4/SkORMSOwc7WhKifnA6Ya33AkzmafA==", + "type": "package", + "path": "system.formats.asn1/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/netcoreapp2.0/System.Formats.Asn1.targets", + "buildTransitive/netcoreapp3.1/_._", + "lib/net461/System.Formats.Asn1.dll", + "lib/net461/System.Formats.Asn1.xml", + "lib/net6.0/System.Formats.Asn1.dll", + "lib/net6.0/System.Formats.Asn1.xml", + "lib/netstandard2.0/System.Formats.Asn1.dll", + "lib/netstandard2.0/System.Formats.Asn1.xml", + "system.formats.asn1.6.0.0.nupkg.sha512", + "system.formats.asn1.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Globalization/4.3.0": { + "sha512": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", + "type": "package", + "path": "system.globalization/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/portable-net45+win8+wp8+wpa81/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/System.Globalization.dll", + "ref/netcore50/System.Globalization.xml", + "ref/netcore50/de/System.Globalization.xml", + "ref/netcore50/es/System.Globalization.xml", + "ref/netcore50/fr/System.Globalization.xml", + "ref/netcore50/it/System.Globalization.xml", + "ref/netcore50/ja/System.Globalization.xml", + "ref/netcore50/ko/System.Globalization.xml", + "ref/netcore50/ru/System.Globalization.xml", + "ref/netcore50/zh-hans/System.Globalization.xml", + "ref/netcore50/zh-hant/System.Globalization.xml", + "ref/netstandard1.0/System.Globalization.dll", + "ref/netstandard1.0/System.Globalization.xml", + "ref/netstandard1.0/de/System.Globalization.xml", + "ref/netstandard1.0/es/System.Globalization.xml", + "ref/netstandard1.0/fr/System.Globalization.xml", + "ref/netstandard1.0/it/System.Globalization.xml", + "ref/netstandard1.0/ja/System.Globalization.xml", + "ref/netstandard1.0/ko/System.Globalization.xml", + "ref/netstandard1.0/ru/System.Globalization.xml", + "ref/netstandard1.0/zh-hans/System.Globalization.xml", + "ref/netstandard1.0/zh-hant/System.Globalization.xml", + "ref/netstandard1.3/System.Globalization.dll", + "ref/netstandard1.3/System.Globalization.xml", + "ref/netstandard1.3/de/System.Globalization.xml", + "ref/netstandard1.3/es/System.Globalization.xml", + "ref/netstandard1.3/fr/System.Globalization.xml", + "ref/netstandard1.3/it/System.Globalization.xml", + "ref/netstandard1.3/ja/System.Globalization.xml", + "ref/netstandard1.3/ko/System.Globalization.xml", + "ref/netstandard1.3/ru/System.Globalization.xml", + "ref/netstandard1.3/zh-hans/System.Globalization.xml", + "ref/netstandard1.3/zh-hant/System.Globalization.xml", + "ref/portable-net45+win8+wp8+wpa81/_._", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.globalization.4.3.0.nupkg.sha512", + "system.globalization.nuspec" + ] + }, + "System.IO/4.3.0": { + "sha512": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", + "type": "package", + "path": "system.io/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/net462/System.IO.dll", + "lib/portable-net45+win8+wp8+wpa81/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/net462/System.IO.dll", + "ref/netcore50/System.IO.dll", + "ref/netcore50/System.IO.xml", + "ref/netcore50/de/System.IO.xml", + "ref/netcore50/es/System.IO.xml", + "ref/netcore50/fr/System.IO.xml", + "ref/netcore50/it/System.IO.xml", + "ref/netcore50/ja/System.IO.xml", + "ref/netcore50/ko/System.IO.xml", + "ref/netcore50/ru/System.IO.xml", + "ref/netcore50/zh-hans/System.IO.xml", + "ref/netcore50/zh-hant/System.IO.xml", + "ref/netstandard1.0/System.IO.dll", + "ref/netstandard1.0/System.IO.xml", + "ref/netstandard1.0/de/System.IO.xml", + "ref/netstandard1.0/es/System.IO.xml", + "ref/netstandard1.0/fr/System.IO.xml", + "ref/netstandard1.0/it/System.IO.xml", + "ref/netstandard1.0/ja/System.IO.xml", + "ref/netstandard1.0/ko/System.IO.xml", + "ref/netstandard1.0/ru/System.IO.xml", + "ref/netstandard1.0/zh-hans/System.IO.xml", + "ref/netstandard1.0/zh-hant/System.IO.xml", + "ref/netstandard1.3/System.IO.dll", + "ref/netstandard1.3/System.IO.xml", + "ref/netstandard1.3/de/System.IO.xml", + "ref/netstandard1.3/es/System.IO.xml", + "ref/netstandard1.3/fr/System.IO.xml", + "ref/netstandard1.3/it/System.IO.xml", + "ref/netstandard1.3/ja/System.IO.xml", + "ref/netstandard1.3/ko/System.IO.xml", + "ref/netstandard1.3/ru/System.IO.xml", + "ref/netstandard1.3/zh-hans/System.IO.xml", + "ref/netstandard1.3/zh-hant/System.IO.xml", + "ref/netstandard1.5/System.IO.dll", + "ref/netstandard1.5/System.IO.xml", + "ref/netstandard1.5/de/System.IO.xml", + "ref/netstandard1.5/es/System.IO.xml", + "ref/netstandard1.5/fr/System.IO.xml", + "ref/netstandard1.5/it/System.IO.xml", + "ref/netstandard1.5/ja/System.IO.xml", + "ref/netstandard1.5/ko/System.IO.xml", + "ref/netstandard1.5/ru/System.IO.xml", + "ref/netstandard1.5/zh-hans/System.IO.xml", + "ref/netstandard1.5/zh-hant/System.IO.xml", + "ref/portable-net45+win8+wp8+wpa81/_._", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.io.4.3.0.nupkg.sha512", + "system.io.nuspec" + ] + }, + "System.IO.FileSystem/4.3.0": { + "sha512": "3wEMARTnuio+ulnvi+hkRNROYwa1kylvYahhcLk4HSoVdl+xxTFVeVlYOfLwrDPImGls0mDqbMhrza8qnWPTdA==", + "type": "package", + "path": "system.io.filesystem/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.IO.FileSystem.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.IO.FileSystem.dll", + "ref/netstandard1.3/System.IO.FileSystem.dll", + "ref/netstandard1.3/System.IO.FileSystem.xml", + "ref/netstandard1.3/de/System.IO.FileSystem.xml", + "ref/netstandard1.3/es/System.IO.FileSystem.xml", + "ref/netstandard1.3/fr/System.IO.FileSystem.xml", + "ref/netstandard1.3/it/System.IO.FileSystem.xml", + "ref/netstandard1.3/ja/System.IO.FileSystem.xml", + "ref/netstandard1.3/ko/System.IO.FileSystem.xml", + "ref/netstandard1.3/ru/System.IO.FileSystem.xml", + "ref/netstandard1.3/zh-hans/System.IO.FileSystem.xml", + "ref/netstandard1.3/zh-hant/System.IO.FileSystem.xml", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.io.filesystem.4.3.0.nupkg.sha512", + "system.io.filesystem.nuspec" + ] + }, + "System.IO.FileSystem.Primitives/4.3.0": { + "sha512": "6QOb2XFLch7bEc4lIcJH49nJN2HV+OC3fHDgsLVsBVBk3Y4hFAnOBGzJ2lUu7CyDDFo9IBWkSsnbkT6IBwwiMw==", + "type": "package", + "path": "system.io.filesystem.primitives/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.IO.FileSystem.Primitives.dll", + "lib/netstandard1.3/System.IO.FileSystem.Primitives.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.IO.FileSystem.Primitives.dll", + "ref/netstandard1.3/System.IO.FileSystem.Primitives.dll", + "ref/netstandard1.3/System.IO.FileSystem.Primitives.xml", + "ref/netstandard1.3/de/System.IO.FileSystem.Primitives.xml", + "ref/netstandard1.3/es/System.IO.FileSystem.Primitives.xml", + "ref/netstandard1.3/fr/System.IO.FileSystem.Primitives.xml", + "ref/netstandard1.3/it/System.IO.FileSystem.Primitives.xml", + "ref/netstandard1.3/ja/System.IO.FileSystem.Primitives.xml", + "ref/netstandard1.3/ko/System.IO.FileSystem.Primitives.xml", + "ref/netstandard1.3/ru/System.IO.FileSystem.Primitives.xml", + "ref/netstandard1.3/zh-hans/System.IO.FileSystem.Primitives.xml", + "ref/netstandard1.3/zh-hant/System.IO.FileSystem.Primitives.xml", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.io.filesystem.primitives.4.3.0.nupkg.sha512", + "system.io.filesystem.primitives.nuspec" + ] + }, + "System.Reactive/6.0.0": { + "sha512": "31kfaW4ZupZzPsI5PVe77VhnvFF55qgma7KZr/E0iFTs6fmdhhG8j0mgEx620iLTey1EynOkEfnyTjtNEpJzGw==", + "type": "package", + "path": "system.reactive/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "build/net6.0-windows10.0.19041/_._", + "build/net6.0/_._", + "buildTransitive/net6.0-windows10.0.19041/_._", + "buildTransitive/net6.0/_._", + "icon.png", + "lib/net472/System.Reactive.dll", + "lib/net472/System.Reactive.xml", + "lib/net6.0-windows10.0.19041/System.Reactive.dll", + "lib/net6.0-windows10.0.19041/System.Reactive.xml", + "lib/net6.0/System.Reactive.dll", + "lib/net6.0/System.Reactive.xml", + "lib/netstandard2.0/System.Reactive.dll", + "lib/netstandard2.0/System.Reactive.xml", + "lib/uap10.0.18362/System.Reactive.dll", + "lib/uap10.0.18362/System.Reactive.pri", + "lib/uap10.0.18362/System.Reactive.xml", + "readme.md", + "system.reactive.6.0.0.nupkg.sha512", + "system.reactive.nuspec" + ] + }, + "System.Reflection/4.3.0": { + "sha512": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", + "type": "package", + "path": "system.reflection/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/net462/System.Reflection.dll", + "lib/portable-net45+win8+wp8+wpa81/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/net462/System.Reflection.dll", + "ref/netcore50/System.Reflection.dll", + "ref/netcore50/System.Reflection.xml", + "ref/netcore50/de/System.Reflection.xml", + "ref/netcore50/es/System.Reflection.xml", + "ref/netcore50/fr/System.Reflection.xml", + "ref/netcore50/it/System.Reflection.xml", + "ref/netcore50/ja/System.Reflection.xml", + "ref/netcore50/ko/System.Reflection.xml", + "ref/netcore50/ru/System.Reflection.xml", + "ref/netcore50/zh-hans/System.Reflection.xml", + "ref/netcore50/zh-hant/System.Reflection.xml", + "ref/netstandard1.0/System.Reflection.dll", + "ref/netstandard1.0/System.Reflection.xml", + "ref/netstandard1.0/de/System.Reflection.xml", + "ref/netstandard1.0/es/System.Reflection.xml", + "ref/netstandard1.0/fr/System.Reflection.xml", + "ref/netstandard1.0/it/System.Reflection.xml", + "ref/netstandard1.0/ja/System.Reflection.xml", + "ref/netstandard1.0/ko/System.Reflection.xml", + "ref/netstandard1.0/ru/System.Reflection.xml", + "ref/netstandard1.0/zh-hans/System.Reflection.xml", + "ref/netstandard1.0/zh-hant/System.Reflection.xml", + "ref/netstandard1.3/System.Reflection.dll", + "ref/netstandard1.3/System.Reflection.xml", + "ref/netstandard1.3/de/System.Reflection.xml", + "ref/netstandard1.3/es/System.Reflection.xml", + "ref/netstandard1.3/fr/System.Reflection.xml", + "ref/netstandard1.3/it/System.Reflection.xml", + "ref/netstandard1.3/ja/System.Reflection.xml", + "ref/netstandard1.3/ko/System.Reflection.xml", + "ref/netstandard1.3/ru/System.Reflection.xml", + "ref/netstandard1.3/zh-hans/System.Reflection.xml", + "ref/netstandard1.3/zh-hant/System.Reflection.xml", + "ref/netstandard1.5/System.Reflection.dll", + "ref/netstandard1.5/System.Reflection.xml", + "ref/netstandard1.5/de/System.Reflection.xml", + "ref/netstandard1.5/es/System.Reflection.xml", + "ref/netstandard1.5/fr/System.Reflection.xml", + "ref/netstandard1.5/it/System.Reflection.xml", + "ref/netstandard1.5/ja/System.Reflection.xml", + "ref/netstandard1.5/ko/System.Reflection.xml", + "ref/netstandard1.5/ru/System.Reflection.xml", + "ref/netstandard1.5/zh-hans/System.Reflection.xml", + "ref/netstandard1.5/zh-hant/System.Reflection.xml", + "ref/portable-net45+win8+wp8+wpa81/_._", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.reflection.4.3.0.nupkg.sha512", + "system.reflection.nuspec" + ] + }, + "System.Reflection.Primitives/4.3.0": { + "sha512": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", + "type": "package", + "path": "system.reflection.primitives/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/portable-net45+win8+wp8+wpa81/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/System.Reflection.Primitives.dll", + "ref/netcore50/System.Reflection.Primitives.xml", + "ref/netcore50/de/System.Reflection.Primitives.xml", + "ref/netcore50/es/System.Reflection.Primitives.xml", + "ref/netcore50/fr/System.Reflection.Primitives.xml", + "ref/netcore50/it/System.Reflection.Primitives.xml", + "ref/netcore50/ja/System.Reflection.Primitives.xml", + "ref/netcore50/ko/System.Reflection.Primitives.xml", + "ref/netcore50/ru/System.Reflection.Primitives.xml", + "ref/netcore50/zh-hans/System.Reflection.Primitives.xml", + "ref/netcore50/zh-hant/System.Reflection.Primitives.xml", + "ref/netstandard1.0/System.Reflection.Primitives.dll", + "ref/netstandard1.0/System.Reflection.Primitives.xml", + "ref/netstandard1.0/de/System.Reflection.Primitives.xml", + "ref/netstandard1.0/es/System.Reflection.Primitives.xml", + "ref/netstandard1.0/fr/System.Reflection.Primitives.xml", + "ref/netstandard1.0/it/System.Reflection.Primitives.xml", + "ref/netstandard1.0/ja/System.Reflection.Primitives.xml", + "ref/netstandard1.0/ko/System.Reflection.Primitives.xml", + "ref/netstandard1.0/ru/System.Reflection.Primitives.xml", + "ref/netstandard1.0/zh-hans/System.Reflection.Primitives.xml", + "ref/netstandard1.0/zh-hant/System.Reflection.Primitives.xml", + "ref/portable-net45+win8+wp8+wpa81/_._", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.reflection.primitives.4.3.0.nupkg.sha512", + "system.reflection.primitives.nuspec" + ] + }, + "System.Resources.ResourceManager/4.3.0": { + "sha512": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", + "type": "package", + "path": "system.resources.resourcemanager/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/portable-net45+win8+wp8+wpa81/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/System.Resources.ResourceManager.dll", + "ref/netcore50/System.Resources.ResourceManager.xml", + "ref/netcore50/de/System.Resources.ResourceManager.xml", + "ref/netcore50/es/System.Resources.ResourceManager.xml", + "ref/netcore50/fr/System.Resources.ResourceManager.xml", + "ref/netcore50/it/System.Resources.ResourceManager.xml", + "ref/netcore50/ja/System.Resources.ResourceManager.xml", + "ref/netcore50/ko/System.Resources.ResourceManager.xml", + "ref/netcore50/ru/System.Resources.ResourceManager.xml", + "ref/netcore50/zh-hans/System.Resources.ResourceManager.xml", + "ref/netcore50/zh-hant/System.Resources.ResourceManager.xml", + "ref/netstandard1.0/System.Resources.ResourceManager.dll", + "ref/netstandard1.0/System.Resources.ResourceManager.xml", + "ref/netstandard1.0/de/System.Resources.ResourceManager.xml", + "ref/netstandard1.0/es/System.Resources.ResourceManager.xml", + "ref/netstandard1.0/fr/System.Resources.ResourceManager.xml", + "ref/netstandard1.0/it/System.Resources.ResourceManager.xml", + "ref/netstandard1.0/ja/System.Resources.ResourceManager.xml", + "ref/netstandard1.0/ko/System.Resources.ResourceManager.xml", + "ref/netstandard1.0/ru/System.Resources.ResourceManager.xml", + "ref/netstandard1.0/zh-hans/System.Resources.ResourceManager.xml", + "ref/netstandard1.0/zh-hant/System.Resources.ResourceManager.xml", + "ref/portable-net45+win8+wp8+wpa81/_._", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.resources.resourcemanager.4.3.0.nupkg.sha512", + "system.resources.resourcemanager.nuspec" + ] + }, + "System.Runtime/4.3.0": { + "sha512": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", + "type": "package", + "path": "system.runtime/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/net462/System.Runtime.dll", + "lib/portable-net45+win8+wp80+wpa81/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/net462/System.Runtime.dll", + "ref/netcore50/System.Runtime.dll", + "ref/netcore50/System.Runtime.xml", + "ref/netcore50/de/System.Runtime.xml", + "ref/netcore50/es/System.Runtime.xml", + "ref/netcore50/fr/System.Runtime.xml", + "ref/netcore50/it/System.Runtime.xml", + "ref/netcore50/ja/System.Runtime.xml", + "ref/netcore50/ko/System.Runtime.xml", + "ref/netcore50/ru/System.Runtime.xml", + "ref/netcore50/zh-hans/System.Runtime.xml", + "ref/netcore50/zh-hant/System.Runtime.xml", + "ref/netstandard1.0/System.Runtime.dll", + "ref/netstandard1.0/System.Runtime.xml", + "ref/netstandard1.0/de/System.Runtime.xml", + "ref/netstandard1.0/es/System.Runtime.xml", + "ref/netstandard1.0/fr/System.Runtime.xml", + "ref/netstandard1.0/it/System.Runtime.xml", + "ref/netstandard1.0/ja/System.Runtime.xml", + "ref/netstandard1.0/ko/System.Runtime.xml", + "ref/netstandard1.0/ru/System.Runtime.xml", + "ref/netstandard1.0/zh-hans/System.Runtime.xml", + "ref/netstandard1.0/zh-hant/System.Runtime.xml", + "ref/netstandard1.2/System.Runtime.dll", + "ref/netstandard1.2/System.Runtime.xml", + "ref/netstandard1.2/de/System.Runtime.xml", + "ref/netstandard1.2/es/System.Runtime.xml", + "ref/netstandard1.2/fr/System.Runtime.xml", + "ref/netstandard1.2/it/System.Runtime.xml", + "ref/netstandard1.2/ja/System.Runtime.xml", + "ref/netstandard1.2/ko/System.Runtime.xml", + "ref/netstandard1.2/ru/System.Runtime.xml", + "ref/netstandard1.2/zh-hans/System.Runtime.xml", + "ref/netstandard1.2/zh-hant/System.Runtime.xml", + "ref/netstandard1.3/System.Runtime.dll", + "ref/netstandard1.3/System.Runtime.xml", + "ref/netstandard1.3/de/System.Runtime.xml", + "ref/netstandard1.3/es/System.Runtime.xml", + "ref/netstandard1.3/fr/System.Runtime.xml", + "ref/netstandard1.3/it/System.Runtime.xml", + "ref/netstandard1.3/ja/System.Runtime.xml", + "ref/netstandard1.3/ko/System.Runtime.xml", + "ref/netstandard1.3/ru/System.Runtime.xml", + "ref/netstandard1.3/zh-hans/System.Runtime.xml", + "ref/netstandard1.3/zh-hant/System.Runtime.xml", + "ref/netstandard1.5/System.Runtime.dll", + "ref/netstandard1.5/System.Runtime.xml", + "ref/netstandard1.5/de/System.Runtime.xml", + "ref/netstandard1.5/es/System.Runtime.xml", + "ref/netstandard1.5/fr/System.Runtime.xml", + "ref/netstandard1.5/it/System.Runtime.xml", + "ref/netstandard1.5/ja/System.Runtime.xml", + "ref/netstandard1.5/ko/System.Runtime.xml", + "ref/netstandard1.5/ru/System.Runtime.xml", + "ref/netstandard1.5/zh-hans/System.Runtime.xml", + "ref/netstandard1.5/zh-hant/System.Runtime.xml", + "ref/portable-net45+win8+wp80+wpa81/_._", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.runtime.4.3.0.nupkg.sha512", + "system.runtime.nuspec" + ] + }, + "System.Runtime.CompilerServices.Unsafe/6.0.0": { + "sha512": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==", + "type": "package", + "path": "system.runtime.compilerservices.unsafe/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.targets", + "buildTransitive/netcoreapp3.1/_._", + "lib/net461/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net461/System.Runtime.CompilerServices.Unsafe.xml", + "lib/net6.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net6.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netcoreapp3.1/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netcoreapp3.1/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512", + "system.runtime.compilerservices.unsafe.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Runtime.Extensions/4.3.0": { + "sha512": "guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", + "type": "package", + "path": "system.runtime.extensions/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/net462/System.Runtime.Extensions.dll", + "lib/portable-net45+win8+wp8+wpa81/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/net462/System.Runtime.Extensions.dll", + "ref/netcore50/System.Runtime.Extensions.dll", + "ref/netcore50/System.Runtime.Extensions.xml", + "ref/netcore50/de/System.Runtime.Extensions.xml", + "ref/netcore50/es/System.Runtime.Extensions.xml", + "ref/netcore50/fr/System.Runtime.Extensions.xml", + "ref/netcore50/it/System.Runtime.Extensions.xml", + "ref/netcore50/ja/System.Runtime.Extensions.xml", + "ref/netcore50/ko/System.Runtime.Extensions.xml", + "ref/netcore50/ru/System.Runtime.Extensions.xml", + "ref/netcore50/zh-hans/System.Runtime.Extensions.xml", + "ref/netcore50/zh-hant/System.Runtime.Extensions.xml", + "ref/netstandard1.0/System.Runtime.Extensions.dll", + "ref/netstandard1.0/System.Runtime.Extensions.xml", + "ref/netstandard1.0/de/System.Runtime.Extensions.xml", + "ref/netstandard1.0/es/System.Runtime.Extensions.xml", + "ref/netstandard1.0/fr/System.Runtime.Extensions.xml", + "ref/netstandard1.0/it/System.Runtime.Extensions.xml", + "ref/netstandard1.0/ja/System.Runtime.Extensions.xml", + "ref/netstandard1.0/ko/System.Runtime.Extensions.xml", + "ref/netstandard1.0/ru/System.Runtime.Extensions.xml", + "ref/netstandard1.0/zh-hans/System.Runtime.Extensions.xml", + "ref/netstandard1.0/zh-hant/System.Runtime.Extensions.xml", + "ref/netstandard1.3/System.Runtime.Extensions.dll", + "ref/netstandard1.3/System.Runtime.Extensions.xml", + "ref/netstandard1.3/de/System.Runtime.Extensions.xml", + "ref/netstandard1.3/es/System.Runtime.Extensions.xml", + "ref/netstandard1.3/fr/System.Runtime.Extensions.xml", + "ref/netstandard1.3/it/System.Runtime.Extensions.xml", + "ref/netstandard1.3/ja/System.Runtime.Extensions.xml", + "ref/netstandard1.3/ko/System.Runtime.Extensions.xml", + "ref/netstandard1.3/ru/System.Runtime.Extensions.xml", + "ref/netstandard1.3/zh-hans/System.Runtime.Extensions.xml", + "ref/netstandard1.3/zh-hant/System.Runtime.Extensions.xml", + "ref/netstandard1.5/System.Runtime.Extensions.dll", + "ref/netstandard1.5/System.Runtime.Extensions.xml", + "ref/netstandard1.5/de/System.Runtime.Extensions.xml", + "ref/netstandard1.5/es/System.Runtime.Extensions.xml", + "ref/netstandard1.5/fr/System.Runtime.Extensions.xml", + "ref/netstandard1.5/it/System.Runtime.Extensions.xml", + "ref/netstandard1.5/ja/System.Runtime.Extensions.xml", + "ref/netstandard1.5/ko/System.Runtime.Extensions.xml", + "ref/netstandard1.5/ru/System.Runtime.Extensions.xml", + "ref/netstandard1.5/zh-hans/System.Runtime.Extensions.xml", + "ref/netstandard1.5/zh-hant/System.Runtime.Extensions.xml", + "ref/portable-net45+win8+wp8+wpa81/_._", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.runtime.extensions.4.3.0.nupkg.sha512", + "system.runtime.extensions.nuspec" + ] + }, + "System.Runtime.Handles/4.3.0": { + "sha512": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", + "type": "package", + "path": "system.runtime.handles/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/_._", + "ref/netstandard1.3/System.Runtime.Handles.dll", + "ref/netstandard1.3/System.Runtime.Handles.xml", + "ref/netstandard1.3/de/System.Runtime.Handles.xml", + "ref/netstandard1.3/es/System.Runtime.Handles.xml", + "ref/netstandard1.3/fr/System.Runtime.Handles.xml", + "ref/netstandard1.3/it/System.Runtime.Handles.xml", + "ref/netstandard1.3/ja/System.Runtime.Handles.xml", + "ref/netstandard1.3/ko/System.Runtime.Handles.xml", + "ref/netstandard1.3/ru/System.Runtime.Handles.xml", + "ref/netstandard1.3/zh-hans/System.Runtime.Handles.xml", + "ref/netstandard1.3/zh-hant/System.Runtime.Handles.xml", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.runtime.handles.4.3.0.nupkg.sha512", + "system.runtime.handles.nuspec" + ] + }, + "System.Runtime.InteropServices/4.3.0": { + "sha512": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", + "type": "package", + "path": "system.runtime.interopservices/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/net462/System.Runtime.InteropServices.dll", + "lib/net463/System.Runtime.InteropServices.dll", + "lib/portable-net45+win8+wpa81/_._", + "lib/win8/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/net462/System.Runtime.InteropServices.dll", + "ref/net463/System.Runtime.InteropServices.dll", + "ref/netcore50/System.Runtime.InteropServices.dll", + "ref/netcore50/System.Runtime.InteropServices.xml", + "ref/netcore50/de/System.Runtime.InteropServices.xml", + "ref/netcore50/es/System.Runtime.InteropServices.xml", + "ref/netcore50/fr/System.Runtime.InteropServices.xml", + "ref/netcore50/it/System.Runtime.InteropServices.xml", + "ref/netcore50/ja/System.Runtime.InteropServices.xml", + "ref/netcore50/ko/System.Runtime.InteropServices.xml", + "ref/netcore50/ru/System.Runtime.InteropServices.xml", + "ref/netcore50/zh-hans/System.Runtime.InteropServices.xml", + "ref/netcore50/zh-hant/System.Runtime.InteropServices.xml", + "ref/netcoreapp1.1/System.Runtime.InteropServices.dll", + "ref/netstandard1.1/System.Runtime.InteropServices.dll", + "ref/netstandard1.1/System.Runtime.InteropServices.xml", + "ref/netstandard1.1/de/System.Runtime.InteropServices.xml", + "ref/netstandard1.1/es/System.Runtime.InteropServices.xml", + "ref/netstandard1.1/fr/System.Runtime.InteropServices.xml", + "ref/netstandard1.1/it/System.Runtime.InteropServices.xml", + "ref/netstandard1.1/ja/System.Runtime.InteropServices.xml", + "ref/netstandard1.1/ko/System.Runtime.InteropServices.xml", + "ref/netstandard1.1/ru/System.Runtime.InteropServices.xml", + "ref/netstandard1.1/zh-hans/System.Runtime.InteropServices.xml", + "ref/netstandard1.1/zh-hant/System.Runtime.InteropServices.xml", + "ref/netstandard1.2/System.Runtime.InteropServices.dll", + "ref/netstandard1.2/System.Runtime.InteropServices.xml", + "ref/netstandard1.2/de/System.Runtime.InteropServices.xml", + "ref/netstandard1.2/es/System.Runtime.InteropServices.xml", + "ref/netstandard1.2/fr/System.Runtime.InteropServices.xml", + "ref/netstandard1.2/it/System.Runtime.InteropServices.xml", + "ref/netstandard1.2/ja/System.Runtime.InteropServices.xml", + "ref/netstandard1.2/ko/System.Runtime.InteropServices.xml", + "ref/netstandard1.2/ru/System.Runtime.InteropServices.xml", + "ref/netstandard1.2/zh-hans/System.Runtime.InteropServices.xml", + "ref/netstandard1.2/zh-hant/System.Runtime.InteropServices.xml", + "ref/netstandard1.3/System.Runtime.InteropServices.dll", + "ref/netstandard1.3/System.Runtime.InteropServices.xml", + "ref/netstandard1.3/de/System.Runtime.InteropServices.xml", + "ref/netstandard1.3/es/System.Runtime.InteropServices.xml", + "ref/netstandard1.3/fr/System.Runtime.InteropServices.xml", + "ref/netstandard1.3/it/System.Runtime.InteropServices.xml", + "ref/netstandard1.3/ja/System.Runtime.InteropServices.xml", + "ref/netstandard1.3/ko/System.Runtime.InteropServices.xml", + "ref/netstandard1.3/ru/System.Runtime.InteropServices.xml", + "ref/netstandard1.3/zh-hans/System.Runtime.InteropServices.xml", + "ref/netstandard1.3/zh-hant/System.Runtime.InteropServices.xml", + "ref/netstandard1.5/System.Runtime.InteropServices.dll", + "ref/netstandard1.5/System.Runtime.InteropServices.xml", + "ref/netstandard1.5/de/System.Runtime.InteropServices.xml", + "ref/netstandard1.5/es/System.Runtime.InteropServices.xml", + "ref/netstandard1.5/fr/System.Runtime.InteropServices.xml", + "ref/netstandard1.5/it/System.Runtime.InteropServices.xml", + "ref/netstandard1.5/ja/System.Runtime.InteropServices.xml", + "ref/netstandard1.5/ko/System.Runtime.InteropServices.xml", + "ref/netstandard1.5/ru/System.Runtime.InteropServices.xml", + "ref/netstandard1.5/zh-hans/System.Runtime.InteropServices.xml", + "ref/netstandard1.5/zh-hant/System.Runtime.InteropServices.xml", + "ref/portable-net45+win8+wpa81/_._", + "ref/win8/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.runtime.interopservices.4.3.0.nupkg.sha512", + "system.runtime.interopservices.nuspec" + ] + }, + "System.Security.Cryptography.Pkcs/6.0.0": { + "sha512": "elM3x+xSRhzQysiqo85SbidJJ2YbZlnvmh+53TuSZHsD7dNuuEWser+9EFtY+rYupBwkq2avc6ZCO3/6qACgmg==", + "type": "package", + "path": "system.security.cryptography.pkcs/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/netcoreapp2.0/System.Security.Cryptography.Pkcs.targets", + "buildTransitive/netcoreapp3.1/_._", + "lib/net461/System.Security.Cryptography.Pkcs.dll", + "lib/net461/System.Security.Cryptography.Pkcs.xml", + "lib/net6.0/System.Security.Cryptography.Pkcs.dll", + "lib/net6.0/System.Security.Cryptography.Pkcs.xml", + "lib/netcoreapp3.1/System.Security.Cryptography.Pkcs.dll", + "lib/netcoreapp3.1/System.Security.Cryptography.Pkcs.xml", + "lib/netstandard2.0/System.Security.Cryptography.Pkcs.dll", + "lib/netstandard2.0/System.Security.Cryptography.Pkcs.xml", + "lib/netstandard2.1/System.Security.Cryptography.Pkcs.dll", + "lib/netstandard2.1/System.Security.Cryptography.Pkcs.xml", + "runtimes/win/lib/net461/System.Security.Cryptography.Pkcs.dll", + "runtimes/win/lib/net461/System.Security.Cryptography.Pkcs.xml", + "runtimes/win/lib/net6.0/System.Security.Cryptography.Pkcs.dll", + "runtimes/win/lib/net6.0/System.Security.Cryptography.Pkcs.xml", + "runtimes/win/lib/netcoreapp3.1/System.Security.Cryptography.Pkcs.dll", + "runtimes/win/lib/netcoreapp3.1/System.Security.Cryptography.Pkcs.xml", + "runtimes/win/lib/netstandard2.0/System.Security.Cryptography.Pkcs.dll", + "runtimes/win/lib/netstandard2.0/System.Security.Cryptography.Pkcs.xml", + "runtimes/win/lib/netstandard2.1/System.Security.Cryptography.Pkcs.dll", + "runtimes/win/lib/netstandard2.1/System.Security.Cryptography.Pkcs.xml", + "system.security.cryptography.pkcs.6.0.0.nupkg.sha512", + "system.security.cryptography.pkcs.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Text.Encoding/4.3.0": { + "sha512": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", + "type": "package", + "path": "system.text.encoding/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/portable-net45+win8+wp8+wpa81/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/System.Text.Encoding.dll", + "ref/netcore50/System.Text.Encoding.xml", + "ref/netcore50/de/System.Text.Encoding.xml", + "ref/netcore50/es/System.Text.Encoding.xml", + "ref/netcore50/fr/System.Text.Encoding.xml", + "ref/netcore50/it/System.Text.Encoding.xml", + "ref/netcore50/ja/System.Text.Encoding.xml", + "ref/netcore50/ko/System.Text.Encoding.xml", + "ref/netcore50/ru/System.Text.Encoding.xml", + "ref/netcore50/zh-hans/System.Text.Encoding.xml", + "ref/netcore50/zh-hant/System.Text.Encoding.xml", + "ref/netstandard1.0/System.Text.Encoding.dll", + "ref/netstandard1.0/System.Text.Encoding.xml", + "ref/netstandard1.0/de/System.Text.Encoding.xml", + "ref/netstandard1.0/es/System.Text.Encoding.xml", + "ref/netstandard1.0/fr/System.Text.Encoding.xml", + "ref/netstandard1.0/it/System.Text.Encoding.xml", + "ref/netstandard1.0/ja/System.Text.Encoding.xml", + "ref/netstandard1.0/ko/System.Text.Encoding.xml", + "ref/netstandard1.0/ru/System.Text.Encoding.xml", + "ref/netstandard1.0/zh-hans/System.Text.Encoding.xml", + "ref/netstandard1.0/zh-hant/System.Text.Encoding.xml", + "ref/netstandard1.3/System.Text.Encoding.dll", + "ref/netstandard1.3/System.Text.Encoding.xml", + "ref/netstandard1.3/de/System.Text.Encoding.xml", + "ref/netstandard1.3/es/System.Text.Encoding.xml", + "ref/netstandard1.3/fr/System.Text.Encoding.xml", + "ref/netstandard1.3/it/System.Text.Encoding.xml", + "ref/netstandard1.3/ja/System.Text.Encoding.xml", + "ref/netstandard1.3/ko/System.Text.Encoding.xml", + "ref/netstandard1.3/ru/System.Text.Encoding.xml", + "ref/netstandard1.3/zh-hans/System.Text.Encoding.xml", + "ref/netstandard1.3/zh-hant/System.Text.Encoding.xml", + "ref/portable-net45+win8+wp8+wpa81/_._", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.text.encoding.4.3.0.nupkg.sha512", + "system.text.encoding.nuspec" + ] + }, + "System.Text.Encoding.CodePages/6.0.0": { + "sha512": "ZFCILZuOvtKPauZ/j/swhvw68ZRi9ATCfvGbk1QfydmcXBkIWecWKn/250UH7rahZ5OoDBaiAudJtPvLwzw85A==", + "type": "package", + "path": "system.text.encoding.codepages/6.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/netcoreapp2.0/System.Text.Encoding.CodePages.targets", + "buildTransitive/netcoreapp3.1/_._", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net461/System.Text.Encoding.CodePages.dll", + "lib/net461/System.Text.Encoding.CodePages.xml", + "lib/net6.0/System.Text.Encoding.CodePages.dll", + "lib/net6.0/System.Text.Encoding.CodePages.xml", + "lib/netcoreapp3.1/System.Text.Encoding.CodePages.dll", + "lib/netcoreapp3.1/System.Text.Encoding.CodePages.xml", + "lib/netstandard2.0/System.Text.Encoding.CodePages.dll", + "lib/netstandard2.0/System.Text.Encoding.CodePages.xml", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "runtimes/win/lib/net461/System.Text.Encoding.CodePages.dll", + "runtimes/win/lib/net461/System.Text.Encoding.CodePages.xml", + "runtimes/win/lib/net6.0/System.Text.Encoding.CodePages.dll", + "runtimes/win/lib/net6.0/System.Text.Encoding.CodePages.xml", + "runtimes/win/lib/netcoreapp3.1/System.Text.Encoding.CodePages.dll", + "runtimes/win/lib/netcoreapp3.1/System.Text.Encoding.CodePages.xml", + "runtimes/win/lib/netstandard2.0/System.Text.Encoding.CodePages.dll", + "runtimes/win/lib/netstandard2.0/System.Text.Encoding.CodePages.xml", + "system.text.encoding.codepages.6.0.0.nupkg.sha512", + "system.text.encoding.codepages.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Text.Encoding.Extensions/4.3.0": { + "sha512": "YVMK0Bt/A43RmwizJoZ22ei2nmrhobgeiYwFzC4YAN+nue8RF6djXDMog0UCn+brerQoYVyaS+ghy9P/MUVcmw==", + "type": "package", + "path": "system.text.encoding.extensions/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/portable-net45+win8+wp8+wpa81/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/System.Text.Encoding.Extensions.dll", + "ref/netcore50/System.Text.Encoding.Extensions.xml", + "ref/netcore50/de/System.Text.Encoding.Extensions.xml", + "ref/netcore50/es/System.Text.Encoding.Extensions.xml", + "ref/netcore50/fr/System.Text.Encoding.Extensions.xml", + "ref/netcore50/it/System.Text.Encoding.Extensions.xml", + "ref/netcore50/ja/System.Text.Encoding.Extensions.xml", + "ref/netcore50/ko/System.Text.Encoding.Extensions.xml", + "ref/netcore50/ru/System.Text.Encoding.Extensions.xml", + "ref/netcore50/zh-hans/System.Text.Encoding.Extensions.xml", + "ref/netcore50/zh-hant/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.0/System.Text.Encoding.Extensions.dll", + "ref/netstandard1.0/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.0/de/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.0/es/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.0/fr/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.0/it/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.0/ja/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.0/ko/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.0/ru/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.0/zh-hans/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.0/zh-hant/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.3/System.Text.Encoding.Extensions.dll", + "ref/netstandard1.3/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.3/de/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.3/es/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.3/fr/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.3/it/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.3/ja/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.3/ko/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.3/ru/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.3/zh-hans/System.Text.Encoding.Extensions.xml", + "ref/netstandard1.3/zh-hant/System.Text.Encoding.Extensions.xml", + "ref/portable-net45+win8+wp8+wpa81/_._", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.text.encoding.extensions.4.3.0.nupkg.sha512", + "system.text.encoding.extensions.nuspec" + ] + }, + "System.Text.Encodings.Web/8.0.0": { + "sha512": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "type": "package", + "path": "system.text.encodings.web/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Text.Encodings.Web.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Text.Encodings.Web.targets", + "lib/net462/System.Text.Encodings.Web.dll", + "lib/net462/System.Text.Encodings.Web.xml", + "lib/net6.0/System.Text.Encodings.Web.dll", + "lib/net6.0/System.Text.Encodings.Web.xml", + "lib/net7.0/System.Text.Encodings.Web.dll", + "lib/net7.0/System.Text.Encodings.Web.xml", + "lib/net8.0/System.Text.Encodings.Web.dll", + "lib/net8.0/System.Text.Encodings.Web.xml", + "lib/netstandard2.0/System.Text.Encodings.Web.dll", + "lib/netstandard2.0/System.Text.Encodings.Web.xml", + "runtimes/browser/lib/net6.0/System.Text.Encodings.Web.dll", + "runtimes/browser/lib/net6.0/System.Text.Encodings.Web.xml", + "runtimes/browser/lib/net7.0/System.Text.Encodings.Web.dll", + "runtimes/browser/lib/net7.0/System.Text.Encodings.Web.xml", + "runtimes/browser/lib/net8.0/System.Text.Encodings.Web.dll", + "runtimes/browser/lib/net8.0/System.Text.Encodings.Web.xml", + "system.text.encodings.web.8.0.0.nupkg.sha512", + "system.text.encodings.web.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Text.Json/8.0.5": { + "sha512": "0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg==", + "type": "package", + "path": "system.text.json/8.0.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "analyzers/dotnet/roslyn3.11/cs/System.Text.Json.SourceGeneration.dll", + "analyzers/dotnet/roslyn3.11/cs/cs/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/de/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/es/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/fr/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/it/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ja/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ko/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/pl/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/pt-BR/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/ru/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/tr/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/zh-Hans/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn3.11/cs/zh-Hant/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/System.Text.Json.SourceGeneration.dll", + "analyzers/dotnet/roslyn4.0/cs/cs/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/de/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/es/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/fr/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/it/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ja/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ko/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/pl/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/pt-BR/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/ru/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/tr/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/zh-Hans/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.0/cs/zh-Hant/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/System.Text.Json.SourceGeneration.dll", + "analyzers/dotnet/roslyn4.4/cs/cs/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/de/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/es/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/fr/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/it/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ja/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ko/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/pl/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/pt-BR/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/ru/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/tr/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/zh-Hans/System.Text.Json.SourceGeneration.resources.dll", + "analyzers/dotnet/roslyn4.4/cs/zh-Hant/System.Text.Json.SourceGeneration.resources.dll", + "buildTransitive/net461/System.Text.Json.targets", + "buildTransitive/net462/System.Text.Json.targets", + "buildTransitive/net6.0/System.Text.Json.targets", + "buildTransitive/netcoreapp2.0/System.Text.Json.targets", + "buildTransitive/netstandard2.0/System.Text.Json.targets", + "lib/net462/System.Text.Json.dll", + "lib/net462/System.Text.Json.xml", + "lib/net6.0/System.Text.Json.dll", + "lib/net6.0/System.Text.Json.xml", + "lib/net7.0/System.Text.Json.dll", + "lib/net7.0/System.Text.Json.xml", + "lib/net8.0/System.Text.Json.dll", + "lib/net8.0/System.Text.Json.xml", + "lib/netstandard2.0/System.Text.Json.dll", + "lib/netstandard2.0/System.Text.Json.xml", + "system.text.json.8.0.5.nupkg.sha512", + "system.text.json.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Threading/4.3.0": { + "sha512": "VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==", + "type": "package", + "path": "system.threading/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/netcore50/System.Threading.dll", + "lib/netstandard1.3/System.Threading.dll", + "lib/portable-net45+win8+wp8+wpa81/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/System.Threading.dll", + "ref/netcore50/System.Threading.xml", + "ref/netcore50/de/System.Threading.xml", + "ref/netcore50/es/System.Threading.xml", + "ref/netcore50/fr/System.Threading.xml", + "ref/netcore50/it/System.Threading.xml", + "ref/netcore50/ja/System.Threading.xml", + "ref/netcore50/ko/System.Threading.xml", + "ref/netcore50/ru/System.Threading.xml", + "ref/netcore50/zh-hans/System.Threading.xml", + "ref/netcore50/zh-hant/System.Threading.xml", + "ref/netstandard1.0/System.Threading.dll", + "ref/netstandard1.0/System.Threading.xml", + "ref/netstandard1.0/de/System.Threading.xml", + "ref/netstandard1.0/es/System.Threading.xml", + "ref/netstandard1.0/fr/System.Threading.xml", + "ref/netstandard1.0/it/System.Threading.xml", + "ref/netstandard1.0/ja/System.Threading.xml", + "ref/netstandard1.0/ko/System.Threading.xml", + "ref/netstandard1.0/ru/System.Threading.xml", + "ref/netstandard1.0/zh-hans/System.Threading.xml", + "ref/netstandard1.0/zh-hant/System.Threading.xml", + "ref/netstandard1.3/System.Threading.dll", + "ref/netstandard1.3/System.Threading.xml", + "ref/netstandard1.3/de/System.Threading.xml", + "ref/netstandard1.3/es/System.Threading.xml", + "ref/netstandard1.3/fr/System.Threading.xml", + "ref/netstandard1.3/it/System.Threading.xml", + "ref/netstandard1.3/ja/System.Threading.xml", + "ref/netstandard1.3/ko/System.Threading.xml", + "ref/netstandard1.3/ru/System.Threading.xml", + "ref/netstandard1.3/zh-hans/System.Threading.xml", + "ref/netstandard1.3/zh-hant/System.Threading.xml", + "ref/portable-net45+win8+wp8+wpa81/_._", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "runtimes/aot/lib/netcore50/System.Threading.dll", + "system.threading.4.3.0.nupkg.sha512", + "system.threading.nuspec" + ] + }, + "System.Threading.Tasks/4.3.0": { + "sha512": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", + "type": "package", + "path": "system.threading.tasks/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/portable-net45+win8+wp8+wpa81/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/System.Threading.Tasks.dll", + "ref/netcore50/System.Threading.Tasks.xml", + "ref/netcore50/de/System.Threading.Tasks.xml", + "ref/netcore50/es/System.Threading.Tasks.xml", + "ref/netcore50/fr/System.Threading.Tasks.xml", + "ref/netcore50/it/System.Threading.Tasks.xml", + "ref/netcore50/ja/System.Threading.Tasks.xml", + "ref/netcore50/ko/System.Threading.Tasks.xml", + "ref/netcore50/ru/System.Threading.Tasks.xml", + "ref/netcore50/zh-hans/System.Threading.Tasks.xml", + "ref/netcore50/zh-hant/System.Threading.Tasks.xml", + "ref/netstandard1.0/System.Threading.Tasks.dll", + "ref/netstandard1.0/System.Threading.Tasks.xml", + "ref/netstandard1.0/de/System.Threading.Tasks.xml", + "ref/netstandard1.0/es/System.Threading.Tasks.xml", + "ref/netstandard1.0/fr/System.Threading.Tasks.xml", + "ref/netstandard1.0/it/System.Threading.Tasks.xml", + "ref/netstandard1.0/ja/System.Threading.Tasks.xml", + "ref/netstandard1.0/ko/System.Threading.Tasks.xml", + "ref/netstandard1.0/ru/System.Threading.Tasks.xml", + "ref/netstandard1.0/zh-hans/System.Threading.Tasks.xml", + "ref/netstandard1.0/zh-hant/System.Threading.Tasks.xml", + "ref/netstandard1.3/System.Threading.Tasks.dll", + "ref/netstandard1.3/System.Threading.Tasks.xml", + "ref/netstandard1.3/de/System.Threading.Tasks.xml", + "ref/netstandard1.3/es/System.Threading.Tasks.xml", + "ref/netstandard1.3/fr/System.Threading.Tasks.xml", + "ref/netstandard1.3/it/System.Threading.Tasks.xml", + "ref/netstandard1.3/ja/System.Threading.Tasks.xml", + "ref/netstandard1.3/ko/System.Threading.Tasks.xml", + "ref/netstandard1.3/ru/System.Threading.Tasks.xml", + "ref/netstandard1.3/zh-hans/System.Threading.Tasks.xml", + "ref/netstandard1.3/zh-hant/System.Threading.Tasks.xml", + "ref/portable-net45+win8+wp8+wpa81/_._", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.threading.tasks.4.3.0.nupkg.sha512", + "system.threading.tasks.nuspec" + ] + }, + "System.Threading.Thread/4.3.0": { + "sha512": "OHmbT+Zz065NKII/ZHcH9XO1dEuLGI1L2k7uYss+9C1jLxTC9kTZZuzUOyXHayRk+dft9CiDf3I/QZ0t8JKyBQ==", + "type": "package", + "path": "system.threading.thread/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Threading.Thread.dll", + "lib/netcore50/_._", + "lib/netstandard1.3/System.Threading.Thread.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Threading.Thread.dll", + "ref/netstandard1.3/System.Threading.Thread.dll", + "ref/netstandard1.3/System.Threading.Thread.xml", + "ref/netstandard1.3/de/System.Threading.Thread.xml", + "ref/netstandard1.3/es/System.Threading.Thread.xml", + "ref/netstandard1.3/fr/System.Threading.Thread.xml", + "ref/netstandard1.3/it/System.Threading.Thread.xml", + "ref/netstandard1.3/ja/System.Threading.Thread.xml", + "ref/netstandard1.3/ko/System.Threading.Thread.xml", + "ref/netstandard1.3/ru/System.Threading.Thread.xml", + "ref/netstandard1.3/zh-hans/System.Threading.Thread.xml", + "ref/netstandard1.3/zh-hant/System.Threading.Thread.xml", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.threading.thread.4.3.0.nupkg.sha512", + "system.threading.thread.nuspec" + ] + }, + "System.Threading.ThreadPool/4.3.0": { + "sha512": "k/+g4b7vjdd4aix83sTgC9VG6oXYKAktSfNIJUNGxPEj7ryEOfzHHhfnmsZvjxawwcD9HyWXKCXmPjX8U4zeSw==", + "type": "package", + "path": "system.threading.threadpool/4.3.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Threading.ThreadPool.dll", + "lib/netcore50/_._", + "lib/netstandard1.3/System.Threading.ThreadPool.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Threading.ThreadPool.dll", + "ref/netstandard1.3/System.Threading.ThreadPool.dll", + "ref/netstandard1.3/System.Threading.ThreadPool.xml", + "ref/netstandard1.3/de/System.Threading.ThreadPool.xml", + "ref/netstandard1.3/es/System.Threading.ThreadPool.xml", + "ref/netstandard1.3/fr/System.Threading.ThreadPool.xml", + "ref/netstandard1.3/it/System.Threading.ThreadPool.xml", + "ref/netstandard1.3/ja/System.Threading.ThreadPool.xml", + "ref/netstandard1.3/ko/System.Threading.ThreadPool.xml", + "ref/netstandard1.3/ru/System.Threading.ThreadPool.xml", + "ref/netstandard1.3/zh-hans/System.Threading.ThreadPool.xml", + "ref/netstandard1.3/zh-hant/System.Threading.ThreadPool.xml", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "system.threading.threadpool.4.3.0.nupkg.sha512", + "system.threading.threadpool.nuspec" + ] + }, + "TimeZoneConverter/6.0.1": { + "sha512": "vvhLOgRSOvfq5fBv0/Dd1S3N7K2ibO5wp06B5AkuxUpXkgv2aDHw9jB5ZvPg83y9sy+jF9qE7qWybMK46BXBuw==", + "type": "package", + "path": "timezoneconverter/6.0.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/TimeZoneConverter.dll", + "lib/net462/TimeZoneConverter.xml", + "lib/net6.0/TimeZoneConverter.dll", + "lib/net6.0/TimeZoneConverter.xml", + "lib/netstandard2.0/TimeZoneConverter.dll", + "lib/netstandard2.0/TimeZoneConverter.xml", + "timezoneconverter.6.0.1.nupkg.sha512", + "timezoneconverter.nuspec" + ] + }, + "YamlDotNet/13.7.1": { + "sha512": "X4m1PnFcJwvAj1sCDMntg/eZcX96CJLrWMiYnq41KqhFVZPuw63ZTSxIGqgdCwHWHvCAyTxheELC/VDf1HsU2A==", + "type": "package", + "path": "yamldotnet/13.7.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.txt", + "images/yamldotnet.png", + "lib/net35/YamlDotNet.dll", + "lib/net35/YamlDotNet.xml", + "lib/net45/YamlDotNet.dll", + "lib/net45/YamlDotNet.xml", + "lib/net47/YamlDotNet.dll", + "lib/net47/YamlDotNet.xml", + "lib/net6.0/YamlDotNet.dll", + "lib/net6.0/YamlDotNet.xml", + "lib/net7.0/YamlDotNet.dll", + "lib/net7.0/YamlDotNet.xml", + "lib/netstandard2.0/YamlDotNet.dll", + "lib/netstandard2.0/YamlDotNet.xml", + "lib/netstandard2.1/YamlDotNet.dll", + "lib/netstandard2.1/YamlDotNet.xml", + "yamldotnet.13.7.1.nupkg.sha512", + "yamldotnet.nuspec" + ] + } + }, + "projectFileDependencyGroups": { + "net6.0": [ + "AspNetCoreRateLimit >= 5.0.0", + "AutoMapper >= 12.0.1", + "Autofac >= 8.1.0", + "Autofac.Extensions.DependencyInjection >= 10.0.0", + "CircularBuffer >= 1.4.0", + "Dapper >= 2.1.35", + "FluentValidation >= 11.10.0", + "FluentValidation.AspNetCore >= 11.3.0", + "FluentValidation.DependencyInjectionExtensions >= 11.10.0", + "GitVersion.MsBuild >= 5.12.0", + "Google.Protobuf >= 3.26.1", + "Grpc.AspNetCore >= 2.57.0", + "Grpc.Net.Client >= 2.62.0", + "Grpc.Tools >= 2.62.0", + "JetBrains.Annotations >= 2024.3.0", + "MailKit >= 3.5.0", + "McMaster.Extensions.CommandLineUtils >= 4.0.2", + "Microsoft.Extensions.Caching.Memory >= 8.0.1", + "Microsoft.Extensions.Configuration.Json >= 8.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions >= 8.0.0", + "Microsoft.IO.RecyclableMemoryStream >= 3.0.0", + "NBitcoin >= 7.0.42", + "NBitcoin.Altcoins >= 3.0.28", + "NBitcoin.Secp256k1 >= 3.1.6", + "NBitcoin.Zcash >= 3.0.0", + "NLog >= 5.3.4", + "NLog.Extensions.Hosting >= 5.3.8", + "NLog.Extensions.Logging >= 5.3.14", + "NSwag.AspNetCore >= 14.0.2", + "NSwag.CodeGeneration.CSharp >= 14.0.2", + "NSwag.MSBuild >= 14.0.2", + "Newtonsoft.Json >= 13.0.3", + "Newtonsoft.Json.Schema >= 4.0.1", + "Npgsql >= 8.0.5", + "Polly >= 8.3.1", + "Portable.BouncyCastle >= 1.9.0", + "System.Diagnostics.Process >= 4.3.0", + "System.Reactive >= 6.0.0", + "prometheus-net >= 8.2.0", + "prometheus-net.AspNetCore >= 8.1.0", + "protobuf-net >= 3.2.30" + ] + }, + "packageFolders": { + "C:\\Users\\Jiegrein\\.nuget\\packages\\": {}, + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\.Freelance\\miningcore\\src\\Miningcore\\Miningcore.csproj", + "projectName": "Miningcore", + "projectPath": "C:\\.Freelance\\miningcore\\src\\Miningcore\\Miningcore.csproj", + "packagesPath": "C:\\Users\\Jiegrein\\.nuget\\packages\\", + "outputPath": "C:\\.Freelance\\miningcore\\src\\Miningcore\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\Jiegrein\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "C:\\.CreditEnable\\Project\\CE.JourneyCRMSync.App\\local_packages": {}, + "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "AspNetCoreRateLimit": { + "target": "Package", + "version": "[5.0.0, )" + }, + "AutoMapper": { + "target": "Package", + "version": "[12.0.1, )" + }, + "Autofac": { + "target": "Package", + "version": "[8.1.0, )" + }, + "Autofac.Extensions.DependencyInjection": { + "target": "Package", + "version": "[10.0.0, )" + }, + "CircularBuffer": { + "target": "Package", + "version": "[1.4.0, )" + }, + "Dapper": { + "target": "Package", + "version": "[2.1.35, )" + }, + "FluentValidation": { + "target": "Package", + "version": "[11.10.0, )" + }, + "FluentValidation.AspNetCore": { + "target": "Package", + "version": "[11.3.0, )" + }, + "FluentValidation.DependencyInjectionExtensions": { + "target": "Package", + "version": "[11.10.0, )" + }, + "GitVersion.MsBuild": { + "include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive", + "suppressParent": "All", + "target": "Package", + "version": "[5.12.0, )" + }, + "Google.Protobuf": { + "target": "Package", + "version": "[3.26.1, )" + }, + "Grpc.AspNetCore": { + "target": "Package", + "version": "[2.57.0, )" + }, + "Grpc.Net.Client": { + "target": "Package", + "version": "[2.62.0, )" + }, + "Grpc.Tools": { + "include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive", + "suppressParent": "All", + "target": "Package", + "version": "[2.62.0, )" + }, + "JetBrains.Annotations": { + "target": "Package", + "version": "[2024.3.0, )" + }, + "MailKit": { + "target": "Package", + "version": "[3.5.0, )" + }, + "McMaster.Extensions.CommandLineUtils": { + "target": "Package", + "version": "[4.0.2, )" + }, + "Microsoft.Extensions.Caching.Memory": { + "target": "Package", + "version": "[8.0.1, )" + }, + "Microsoft.Extensions.Configuration.Json": { + "target": "Package", + "version": "[8.0.0, )" + }, + "Microsoft.Extensions.Options.ConfigurationExtensions": { + "target": "Package", + "version": "[8.0.0, )" + }, + "Microsoft.IO.RecyclableMemoryStream": { + "target": "Package", + "version": "[3.0.0, )" + }, + "NBitcoin": { + "target": "Package", + "version": "[7.0.42, )" + }, + "NBitcoin.Altcoins": { + "target": "Package", + "version": "[3.0.28, )" + }, + "NBitcoin.Secp256k1": { + "target": "Package", + "version": "[3.1.6, )" + }, + "NBitcoin.Zcash": { + "target": "Package", + "version": "[3.0.0, )" + }, + "NLog": { + "target": "Package", + "version": "[5.3.4, )" + }, + "NLog.Extensions.Hosting": { + "target": "Package", + "version": "[5.3.8, )" + }, + "NLog.Extensions.Logging": { + "target": "Package", + "version": "[5.3.14, )" + }, + "NSwag.AspNetCore": { + "target": "Package", + "version": "[14.0.2, )" + }, + "NSwag.CodeGeneration.CSharp": { + "target": "Package", + "version": "[14.0.2, )" + }, + "NSwag.MSBuild": { + "include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive", + "suppressParent": "All", + "target": "Package", + "version": "[14.0.2, )" + }, + "Newtonsoft.Json": { + "target": "Package", + "version": "[13.0.3, )" + }, + "Newtonsoft.Json.Schema": { + "target": "Package", + "version": "[4.0.1, )" + }, + "Npgsql": { + "target": "Package", + "version": "[8.0.5, )" + }, + "Polly": { + "target": "Package", + "version": "[8.3.1, )" + }, + "Portable.BouncyCastle": { + "target": "Package", + "version": "[1.9.0, )" + }, + "System.Diagnostics.Process": { + "target": "Package", + "version": "[4.3.0, )" + }, + "System.Reactive": { + "target": "Package", + "version": "[6.0.0, )" + }, + "prometheus-net": { + "target": "Package", + "version": "[8.2.0, )" + }, + "prometheus-net.AspNetCore": { + "target": "Package", + "version": "[8.1.0, )" + }, + "protobuf-net": { + "target": "Package", + "version": "[3.2.30, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.101\\RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/src/Miningcore/obj/project.nuget.cache b/src/Miningcore/obj/project.nuget.cache new file mode 100644 index 0000000000..b54976539e --- /dev/null +++ b/src/Miningcore/obj/project.nuget.cache @@ -0,0 +1,130 @@ +{ + "version": 2, + "dgSpecHash": "4u8PoAuT+ro=", + "success": true, + "projectFilePath": "C:\\.Freelance\\miningcore\\src\\Miningcore\\Miningcore.csproj", + "expectedPackageFiles": [ + "C:\\Users\\Jiegrein\\.nuget\\packages\\aspnetcoreratelimit\\5.0.0\\aspnetcoreratelimit.5.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\autofac\\8.1.0\\autofac.8.1.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\autofac.extensions.dependencyinjection\\10.0.0\\autofac.extensions.dependencyinjection.10.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\automapper\\12.0.1\\automapper.12.0.1.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\circularbuffer\\1.4.0\\circularbuffer.1.4.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\dapper\\2.1.35\\dapper.2.1.35.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\fluentvalidation\\11.10.0\\fluentvalidation.11.10.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\fluentvalidation.aspnetcore\\11.3.0\\fluentvalidation.aspnetcore.11.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\fluentvalidation.dependencyinjectionextensions\\11.10.0\\fluentvalidation.dependencyinjectionextensions.11.10.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\fluid.core\\2.5.0\\fluid.core.2.5.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\gitversion.msbuild\\5.12.0\\gitversion.msbuild.5.12.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\google.protobuf\\3.26.1\\google.protobuf.3.26.1.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\grpc.aspnetcore\\2.57.0\\grpc.aspnetcore.2.57.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\grpc.aspnetcore.server\\2.57.0\\grpc.aspnetcore.server.2.57.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\grpc.aspnetcore.server.clientfactory\\2.57.0\\grpc.aspnetcore.server.clientfactory.2.57.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\grpc.core.api\\2.62.0\\grpc.core.api.2.62.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\grpc.net.client\\2.62.0\\grpc.net.client.2.62.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\grpc.net.clientfactory\\2.57.0\\grpc.net.clientfactory.2.57.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\grpc.net.common\\2.62.0\\grpc.net.common.2.62.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\grpc.tools\\2.62.0\\grpc.tools.2.62.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\jetbrains.annotations\\2024.3.0\\jetbrains.annotations.2024.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\mailkit\\3.5.0\\mailkit.3.5.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\mcmaster.extensions.commandlineutils\\4.0.2\\mcmaster.extensions.commandlineutils.4.0.2.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.bcl.asyncinterfaces\\6.0.0\\microsoft.bcl.asyncinterfaces.6.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.bcl.timeprovider\\8.0.0\\microsoft.bcl.timeprovider.8.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.csharp\\4.7.0\\microsoft.csharp.4.7.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.apidescription.server\\6.0.3\\microsoft.extensions.apidescription.server.6.0.3.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.caching.abstractions\\8.0.0\\microsoft.extensions.caching.abstractions.8.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.caching.memory\\8.0.1\\microsoft.extensions.caching.memory.8.0.1.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.configuration\\8.0.0\\microsoft.extensions.configuration.8.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.configuration.abstractions\\8.0.0\\microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.configuration.binder\\8.0.0\\microsoft.extensions.configuration.binder.8.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.configuration.fileextensions\\8.0.0\\microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.configuration.json\\8.0.0\\microsoft.extensions.configuration.json.8.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.dependencyinjection\\6.0.0\\microsoft.extensions.dependencyinjection.6.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.dependencyinjection.abstractions\\8.0.2\\microsoft.extensions.dependencyinjection.abstractions.8.0.2.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.fileproviders.abstractions\\8.0.0\\microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.fileproviders.embedded\\6.0.0\\microsoft.extensions.fileproviders.embedded.6.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.fileproviders.physical\\8.0.0\\microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.filesystemglobbing\\8.0.0\\microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.hosting.abstractions\\6.0.0\\microsoft.extensions.hosting.abstractions.6.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.http\\6.0.0\\microsoft.extensions.http.6.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.logging\\6.0.0\\microsoft.extensions.logging.6.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.logging.abstractions\\8.0.2\\microsoft.extensions.logging.abstractions.8.0.2.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.objectpool\\7.0.0\\microsoft.extensions.objectpool.7.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.options\\8.0.2\\microsoft.extensions.options.8.0.2.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.options.configurationextensions\\8.0.0\\microsoft.extensions.options.configurationextensions.8.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.extensions.primitives\\8.0.0\\microsoft.extensions.primitives.8.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.io.recyclablememorystream\\3.0.0\\microsoft.io.recyclablememorystream.3.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.netcore.platforms\\1.1.0\\microsoft.netcore.platforms.1.1.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.netcore.targets\\1.1.0\\microsoft.netcore.targets.1.1.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.win32.primitives\\4.3.0\\microsoft.win32.primitives.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\microsoft.win32.registry\\4.3.0\\microsoft.win32.registry.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\mimekit\\3.5.0\\mimekit.3.5.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\namotion.reflection\\3.1.1\\namotion.reflection.3.1.1.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nbitcoin\\7.0.42\\nbitcoin.7.0.42.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nbitcoin.altcoins\\3.0.28\\nbitcoin.altcoins.3.0.28.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nbitcoin.secp256k1\\3.1.6\\nbitcoin.secp256k1.3.1.6.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nbitcoin.zcash\\3.0.0\\nbitcoin.zcash.3.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\newtonsoft.json\\13.0.3\\newtonsoft.json.13.0.3.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\newtonsoft.json.schema\\4.0.1\\newtonsoft.json.schema.4.0.1.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\njsonschema\\11.0.0\\njsonschema.11.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\njsonschema.annotations\\11.0.0\\njsonschema.annotations.11.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\njsonschema.codegeneration\\11.0.0\\njsonschema.codegeneration.11.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\njsonschema.codegeneration.csharp\\11.0.0\\njsonschema.codegeneration.csharp.11.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\njsonschema.newtonsoftjson\\11.0.0\\njsonschema.newtonsoftjson.11.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\njsonschema.yaml\\11.0.0\\njsonschema.yaml.11.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nlog\\5.3.4\\nlog.5.3.4.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nlog.extensions.hosting\\5.3.8\\nlog.extensions.hosting.5.3.8.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nlog.extensions.logging\\5.3.14\\nlog.extensions.logging.5.3.14.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\npgsql\\8.0.5\\npgsql.8.0.5.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nswag.annotations\\14.0.2\\nswag.annotations.14.0.2.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nswag.aspnetcore\\14.0.2\\nswag.aspnetcore.14.0.2.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nswag.codegeneration\\14.0.2\\nswag.codegeneration.14.0.2.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nswag.codegeneration.csharp\\14.0.2\\nswag.codegeneration.csharp.14.0.2.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nswag.core\\14.0.2\\nswag.core.14.0.2.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nswag.core.yaml\\14.0.2\\nswag.core.yaml.14.0.2.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nswag.generation\\14.0.2\\nswag.generation.14.0.2.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nswag.generation.aspnetcore\\14.0.2\\nswag.generation.aspnetcore.14.0.2.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\nswag.msbuild\\14.0.2\\nswag.msbuild.14.0.2.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\parlot\\0.0.24\\parlot.0.0.24.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\polly\\8.3.1\\polly.8.3.1.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\polly.core\\8.3.1\\polly.core.8.3.1.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\portable.bouncycastle\\1.9.0\\portable.bouncycastle.1.9.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\prometheus-net\\8.2.0\\prometheus-net.8.2.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\prometheus-net.aspnetcore\\8.1.0\\prometheus-net.aspnetcore.8.1.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\protobuf-net\\3.2.30\\protobuf-net.3.2.30.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\protobuf-net.core\\3.2.30\\protobuf-net.core.3.2.30.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\runtime.native.system\\4.3.0\\runtime.native.system.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.collections\\4.3.0\\system.collections.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.collections.immutable\\7.0.0\\system.collections.immutable.7.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.componentmodel.annotations\\5.0.0\\system.componentmodel.annotations.5.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.diagnostics.debug\\4.3.0\\system.diagnostics.debug.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.diagnostics.diagnosticsource\\8.0.1\\system.diagnostics.diagnosticsource.8.0.1.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.diagnostics.process\\4.3.0\\system.diagnostics.process.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.formats.asn1\\6.0.0\\system.formats.asn1.6.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.globalization\\4.3.0\\system.globalization.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.io\\4.3.0\\system.io.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.io.filesystem\\4.3.0\\system.io.filesystem.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.io.filesystem.primitives\\4.3.0\\system.io.filesystem.primitives.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.reactive\\6.0.0\\system.reactive.6.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.reflection\\4.3.0\\system.reflection.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.reflection.primitives\\4.3.0\\system.reflection.primitives.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.resources.resourcemanager\\4.3.0\\system.resources.resourcemanager.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.runtime\\4.3.0\\system.runtime.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.runtime.compilerservices.unsafe\\6.0.0\\system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.runtime.extensions\\4.3.0\\system.runtime.extensions.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.runtime.handles\\4.3.0\\system.runtime.handles.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.runtime.interopservices\\4.3.0\\system.runtime.interopservices.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.security.cryptography.pkcs\\6.0.0\\system.security.cryptography.pkcs.6.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.text.encoding\\4.3.0\\system.text.encoding.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.text.encoding.codepages\\6.0.0\\system.text.encoding.codepages.6.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.text.encoding.extensions\\4.3.0\\system.text.encoding.extensions.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.text.encodings.web\\8.0.0\\system.text.encodings.web.8.0.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.text.json\\8.0.5\\system.text.json.8.0.5.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.threading\\4.3.0\\system.threading.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.threading.tasks\\4.3.0\\system.threading.tasks.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.threading.thread\\4.3.0\\system.threading.thread.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\system.threading.threadpool\\4.3.0\\system.threading.threadpool.4.3.0.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\timezoneconverter\\6.0.1\\timezoneconverter.6.0.1.nupkg.sha512", + "C:\\Users\\Jiegrein\\.nuget\\packages\\yamldotnet\\13.7.1\\yamldotnet.13.7.1.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/src/Native/libbeamhash/Makefile b/src/Native/libbeamhash/Makefile index 44685206a0..cb89346d48 100644 --- a/src/Native/libbeamhash/Makefile +++ b/src/Native/libbeamhash/Makefile @@ -3,7 +3,7 @@ CXXFLAGS += -g -Wall -fPIC -fpermissive -O2 -funroll-loops -fomit-frame-pointer LDFLAGS += -shared TARGET = libbeamhash.so -OBJECTS = beam/core/difficulty.o beam/core/uintBig.o beam/utility/common.o crypto/blake/sse/blake2b.o crypto/beamHashIII.o crypto/equihashR.o support/cleanse.o arith_uint256.o beamhashverify.o exports.o random.o uint256.o util.o utilstrencodings.o +OBJECTS = blake/blake2b.o beamHashIII_imp.o beamhashverify.o equihashR_imp.o exports.o all: $(TARGET) diff --git a/src/Native/libbeamhash/arith_uint256.cpp b/src/Native/libbeamhash/arith_uint256.cpp deleted file mode 100644 index 2e61363576..0000000000 --- a/src/Native/libbeamhash/arith_uint256.cpp +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "arith_uint256.h" - -#include "uint256.h" -#include "utilstrencodings.h" -#include "crypto/common.h" - -#include -#include - -template -base_uint::base_uint(const std::string& str) -{ - SetHex(str); -} - -template -base_uint& base_uint::operator<<=(unsigned int shift) -{ - base_uint a(*this); - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - int k = shift / 32; - shift = shift % 32; - for (int i = 0; i < WIDTH; i++) { - if (i + k + 1 < WIDTH && shift != 0) - pn[i + k + 1] |= (a.pn[i] >> (32 - shift)); - if (i + k < WIDTH) - pn[i + k] |= (a.pn[i] << shift); - } - return *this; -} - -template -base_uint& base_uint::operator>>=(unsigned int shift) -{ - base_uint a(*this); - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - int k = shift / 32; - shift = shift % 32; - for (int i = 0; i < WIDTH; i++) { - if (i - k - 1 >= 0 && shift != 0) - pn[i - k - 1] |= (a.pn[i] << (32 - shift)); - if (i - k >= 0) - pn[i - k] |= (a.pn[i] >> shift); - } - return *this; -} - -template -base_uint& base_uint::operator*=(uint32_t b32) -{ - uint64_t carry = 0; - for (int i = 0; i < WIDTH; i++) { - uint64_t n = carry + (uint64_t)b32 * pn[i]; - pn[i] = n & 0xffffffff; - carry = n >> 32; - } - return *this; -} - -template -base_uint& base_uint::operator*=(const base_uint& b) -{ - base_uint a = *this; - *this = 0; - for (int j = 0; j < WIDTH; j++) { - uint64_t carry = 0; - for (int i = 0; i + j < WIDTH; i++) { - uint64_t n = carry + pn[i + j] + (uint64_t)a.pn[j] * b.pn[i]; - pn[i + j] = n & 0xffffffff; - carry = n >> 32; - } - } - return *this; -} - -template -base_uint& base_uint::operator/=(const base_uint& b) -{ - base_uint div = b; // make a copy, so we can shift. - base_uint num = *this; // make a copy, so we can subtract. - *this = 0; // the quotient. - int num_bits = num.bits(); - int div_bits = div.bits(); - if (div_bits == 0) - throw uint_error("Division by zero"); - if (div_bits > num_bits) // the result is certainly 0. - return *this; - int shift = num_bits - div_bits; - div <<= shift; // shift so that div and num align. - while (shift >= 0) { - if (num >= div) { - num -= div; - pn[shift / 32] |= (1 << (shift & 31)); // set a bit of the result. - } - div >>= 1; // shift back. - shift--; - } - // num now contains the remainder of the division. - return *this; -} - -template -int base_uint::CompareTo(const base_uint& b) const -{ - for (int i = WIDTH - 1; i >= 0; i--) { - if (pn[i] < b.pn[i]) - return -1; - if (pn[i] > b.pn[i]) - return 1; - } - return 0; -} - -template -bool base_uint::EqualTo(uint64_t b) const -{ - for (int i = WIDTH - 1; i >= 2; i--) { - if (pn[i]) - return false; - } - if (pn[1] != (b >> 32)) - return false; - if (pn[0] != (b & 0xfffffffful)) - return false; - return true; -} - -template -double base_uint::getdouble() const -{ - double ret = 0.0; - double fact = 1.0; - for (int i = 0; i < WIDTH; i++) { - ret += fact * pn[i]; - fact *= 4294967296.0; - } - return ret; -} - -template -std::string base_uint::GetHex() const -{ - return ArithToUint256(*this).GetHex(); -} - -template -void base_uint::SetHex(const char* psz) -{ - *this = UintToArith256(uint256S(psz)); -} - -template -void base_uint::SetHex(const std::string& str) -{ - SetHex(str.c_str()); -} - -template -std::string base_uint::ToString() const -{ - return (GetHex()); -} - -template -unsigned int base_uint::bits() const -{ - for (int pos = WIDTH - 1; pos >= 0; pos--) { - if (pn[pos]) { - for (int bits = 31; bits > 0; bits--) { - if (pn[pos] & 1 << bits) - return 32 * pos + bits + 1; - } - return 32 * pos + 1; - } - } - return 0; -} - -// Explicit instantiations for base_uint<256> -template base_uint<256>::base_uint(const std::string&); -template base_uint<256>& base_uint<256>::operator<<=(unsigned int); -template base_uint<256>& base_uint<256>::operator>>=(unsigned int); -template base_uint<256>& base_uint<256>::operator*=(uint32_t b32); -template base_uint<256>& base_uint<256>::operator*=(const base_uint<256>& b); -template base_uint<256>& base_uint<256>::operator/=(const base_uint<256>& b); -template int base_uint<256>::CompareTo(const base_uint<256>&) const; -template bool base_uint<256>::EqualTo(uint64_t) const; -template double base_uint<256>::getdouble() const; -template std::string base_uint<256>::GetHex() const; -template std::string base_uint<256>::ToString() const; -template void base_uint<256>::SetHex(const char*); -template void base_uint<256>::SetHex(const std::string&); -template unsigned int base_uint<256>::bits() const; - -// This implementation directly uses shifts instead of going -// through an intermediate MPI representation. -arith_uint256& arith_uint256::SetCompact(uint32_t nCompact, bool* pfNegative, bool* pfOverflow) -{ - int nSize = nCompact >> 24; - uint32_t nWord = nCompact & 0x007fffff; - if (nSize <= 3) { - nWord >>= 8 * (3 - nSize); - *this = nWord; - } else { - *this = nWord; - *this <<= 8 * (nSize - 3); - } - if (pfNegative) - *pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0; - if (pfOverflow) - *pfOverflow = nWord != 0 && ((nSize > 34) || - (nWord > 0xff && nSize > 33) || - (nWord > 0xffff && nSize > 32)); - return *this; -} - -uint32_t arith_uint256::GetCompact(bool fNegative) const -{ - int nSize = (bits() + 7) / 8; - uint32_t nCompact = 0; - if (nSize <= 3) { - nCompact = GetLow64() << 8 * (3 - nSize); - } else { - arith_uint256 bn = *this >> 8 * (nSize - 3); - nCompact = bn.GetLow64(); - } - // The 0x00800000 bit denotes the sign. - // Thus, if it is already set, divide the mantissa by 256 and increase the exponent. - if (nCompact & 0x00800000) { - nCompact >>= 8; - nSize++; - } - assert((nCompact & ~0x007fffff) == 0); - assert(nSize < 256); - nCompact |= nSize << 24; - nCompact |= (fNegative && (nCompact & 0x007fffff) ? 0x00800000 : 0); - return nCompact; -} - -uint256 ArithToUint256(const arith_uint256 &a) -{ - uint256 b; - for(int x=0; x -#include -#include -#include -#include -#include - -class uint256; - -class uint_error : public std::runtime_error { -public: - explicit uint_error(const std::string& str) : std::runtime_error(str) {} -}; - -/** Template base class for unsigned big integers. */ -template -class base_uint -{ -protected: - enum { WIDTH=BITS/32 }; - uint32_t pn[WIDTH]; -public: - - base_uint() - { - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - } - - base_uint(const base_uint& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - } - - base_uint& operator=(const base_uint& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - return *this; - } - - base_uint(uint64_t b) - { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - } - - explicit base_uint(const std::string& str); - - bool operator!() const - { - for (int i = 0; i < WIDTH; i++) - if (pn[i] != 0) - return false; - return true; - } - - const base_uint operator~() const - { - base_uint ret; - for (int i = 0; i < WIDTH; i++) - ret.pn[i] = ~pn[i]; - return ret; - } - - const base_uint operator-() const - { - base_uint ret; - for (int i = 0; i < WIDTH; i++) - ret.pn[i] = ~pn[i]; - ret++; - return ret; - } - - double getdouble() const; - - base_uint& operator=(uint64_t b) - { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - return *this; - } - - base_uint& operator^=(const base_uint& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] ^= b.pn[i]; - return *this; - } - - base_uint& operator&=(const base_uint& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] &= b.pn[i]; - return *this; - } - - base_uint& operator|=(const base_uint& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] |= b.pn[i]; - return *this; - } - - base_uint& operator^=(uint64_t b) - { - pn[0] ^= (unsigned int)b; - pn[1] ^= (unsigned int)(b >> 32); - return *this; - } - - base_uint& operator|=(uint64_t b) - { - pn[0] |= (unsigned int)b; - pn[1] |= (unsigned int)(b >> 32); - return *this; - } - - base_uint& operator<<=(unsigned int shift); - base_uint& operator>>=(unsigned int shift); - - base_uint& operator+=(const base_uint& b) - { - uint64_t carry = 0; - for (int i = 0; i < WIDTH; i++) - { - uint64_t n = carry + pn[i] + b.pn[i]; - pn[i] = n & 0xffffffff; - carry = n >> 32; - } - return *this; - } - - base_uint& operator-=(const base_uint& b) - { - *this += -b; - return *this; - } - - base_uint& operator+=(uint64_t b64) - { - base_uint b; - b = b64; - *this += b; - return *this; - } - - base_uint& operator-=(uint64_t b64) - { - base_uint b; - b = b64; - *this += -b; - return *this; - } - - base_uint& operator*=(uint32_t b32); - base_uint& operator*=(const base_uint& b); - base_uint& operator/=(const base_uint& b); - - base_uint& operator++() - { - // prefix operator - int i = 0; - while (++pn[i] == 0 && i < WIDTH-1) - i++; - return *this; - } - - const base_uint operator++(int) - { - // postfix operator - const base_uint ret = *this; - ++(*this); - return ret; - } - - base_uint& operator--() - { - // prefix operator - int i = 0; - while (--pn[i] == (uint32_t)-1 && i < WIDTH-1) - i++; - return *this; - } - - const base_uint operator--(int) - { - // postfix operator - const base_uint ret = *this; - --(*this); - return ret; - } - - int CompareTo(const base_uint& b) const; - bool EqualTo(uint64_t b) const; - - friend inline const base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; } - friend inline const base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; } - friend inline const base_uint operator*(const base_uint& a, const base_uint& b) { return base_uint(a) *= b; } - friend inline const base_uint operator/(const base_uint& a, const base_uint& b) { return base_uint(a) /= b; } - friend inline const base_uint operator|(const base_uint& a, const base_uint& b) { return base_uint(a) |= b; } - friend inline const base_uint operator&(const base_uint& a, const base_uint& b) { return base_uint(a) &= b; } - friend inline const base_uint operator^(const base_uint& a, const base_uint& b) { return base_uint(a) ^= b; } - friend inline const base_uint operator>>(const base_uint& a, int shift) { return base_uint(a) >>= shift; } - friend inline const base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; } - friend inline const base_uint operator*(const base_uint& a, uint32_t b) { return base_uint(a) *= b; } - friend inline bool operator==(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) == 0; } - friend inline bool operator!=(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) != 0; } - friend inline bool operator>(const base_uint& a, const base_uint& b) { return a.CompareTo(b) > 0; } - friend inline bool operator<(const base_uint& a, const base_uint& b) { return a.CompareTo(b) < 0; } - friend inline bool operator>=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) >= 0; } - friend inline bool operator<=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) <= 0; } - friend inline bool operator==(const base_uint& a, uint64_t b) { return a.EqualTo(b); } - friend inline bool operator!=(const base_uint& a, uint64_t b) { return !a.EqualTo(b); } - - std::string GetHex() const; - void SetHex(const char* psz); - void SetHex(const std::string& str); - std::string ToString() const; - - unsigned int size() const - { - return sizeof(pn); - } - - /** - * Returns the position of the highest bit set plus one, or zero if the - * value is zero. - */ - unsigned int bits() const; - - uint64_t GetLow64() const - { - assert(WIDTH >= 2); - return pn[0] | (uint64_t)pn[1] << 32; - } -}; - -/** 256-bit unsigned big integer. */ -class arith_uint256 : public base_uint<256> { -public: - arith_uint256() {} - arith_uint256(const base_uint<256>& b) : base_uint<256>(b) {} - arith_uint256(uint64_t b) : base_uint<256>(b) {} - explicit arith_uint256(const std::string& str) : base_uint<256>(str) {} - - /** - * The "compact" format is a representation of a whole - * number N using an unsigned 32bit number similar to a - * floating point format. - * The most significant 8 bits are the unsigned exponent of base 256. - * This exponent can be thought of as "number of bytes of N". - * The lower 23 bits are the mantissa. - * Bit number 24 (0x800000) represents the sign of N. - * N = (-1^sign) * mantissa * 256^(exponent-3) - * - * Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). - * MPI uses the most significant bit of the first byte as sign. - * Thus 0x1234560000 is compact (0x05123456) - * and 0xc0de000000 is compact (0x0600c0de) - * - * Bitcoin only uses this "compact" format for encoding difficulty - * targets, which are unsigned 256bit quantities. Thus, all the - * complexities of the sign bit and using base 256 are probably an - * implementation accident. - */ - arith_uint256& SetCompact(uint32_t nCompact, bool *pfNegative = NULL, bool *pfOverflow = NULL); - uint32_t GetCompact(bool fNegative = false) const; - - friend uint256 ArithToUint256(const arith_uint256 &); - friend arith_uint256 UintToArith256(const uint256 &); -}; - -uint256 ArithToUint256(const arith_uint256 &); -arith_uint256 UintToArith256(const uint256 &); - -#endif // BITCOIN_ARITH_UINT256_H diff --git a/src/Native/libbeamhash/beam/core/common.h b/src/Native/libbeamhash/beam/core/common.h deleted file mode 100644 index 23c06aa6f1..0000000000 --- a/src/Native/libbeamhash/beam/core/common.h +++ /dev/null @@ -1 +0,0 @@ -#include "../utility/common.h" diff --git a/src/Native/libbeamhash/beam/core/difficulty.cpp b/src/Native/libbeamhash/beam/core/difficulty.cpp deleted file mode 100644 index d40d9ab84a..0000000000 --- a/src/Native/libbeamhash/beam/core/difficulty.cpp +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright 2018 The Beam Team -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 "difficulty.h" -#include - -namespace beam -{ - void Difficulty::Pack(uint32_t order, uint32_t mantissa) - { - if (order <= s_MaxOrder) - { - assert((mantissa >> s_MantissaBits) == 1U); - mantissa &= (1U << s_MantissaBits) - 1; - - m_Packed = mantissa | (order << s_MantissaBits); - } - else - m_Packed = s_Inf; - } - - void Difficulty::Unpack(uint32_t& order, uint32_t& mantissa) const - { - order = (m_Packed >> s_MantissaBits); - - const uint32_t nLeadingBit = 1U << s_MantissaBits; - mantissa = nLeadingBit | (m_Packed & (nLeadingBit - 1)); - } - - bool Difficulty::IsTargetReached(const beam::uintBig_t<32>& hv) const - { - if (m_Packed > s_Inf) - return false; // invalid - - // multiply by (raw) difficulty, check if the result fits wrt normalization. - Raw val; - Unpack(val); - - auto a = hv * val; // would be 512 bits - - static_assert(!(s_MantissaBits & 7), ""); // fix the following code lines to support non-byte-aligned mantissa size - - return memis0(a.m_pData, Raw::nBytes - (s_MantissaBits >> 3)); - } - - void Difficulty::Unpack(Raw& res) const - { - res = Zero; - if (m_Packed < s_Inf) - { - uint32_t order, mantissa; - Unpack(order, mantissa); - res.AssignSafe(mantissa, order); - - } - else - res.Inv(); - } - - Difficulty::Raw operator + (const Difficulty::Raw& base, const Difficulty& d) - { - Difficulty::Raw res; - d.Unpack(res); - res += base; - return res; - } - - Difficulty::Raw& operator += (Difficulty::Raw& res, const Difficulty& d) - { - Difficulty::Raw base; - d.Unpack(base); - res += base; - return res; - } - - Difficulty::Raw operator - (const Difficulty::Raw& base, const Difficulty& d) - { - Difficulty::Raw res; - d.Unpack(res); - res.Negate(); - res += base; - return res; - } - - Difficulty::Raw& operator -= (Difficulty::Raw& res, const Difficulty& d) - { - Difficulty::Raw base; - d.Unpack(base); - base.Negate(); - res += base; - return res; - } - - struct Difficulty::BigFloat - { - int m_Order; // signed - uint32_t m_Value; - static const uint32_t nBits = sizeof(uint32_t) << 3; - - template - void operator = (const uintBig_t& val) - { - uint32_t nOrder = val.get_Order(); - if (nOrder) - { - m_Order = nOrder - nBits; - - uintBigFor::Type x; - if (m_Order > 0) - val.ShiftRight(m_Order, x); - else - val.ShiftLeft(-m_Order, x); - - x.Export(m_Value); - } - else - { - m_Order = 0; - m_Value = 0; - } - } - - template - void operator = (T val) - { - *this = typename uintBigFor::Type(val); - } - - BigFloat operator * (const BigFloat& x) const - { - uint64_t val = m_Value; - val *= x.m_Value; - - BigFloat res(val); - res.m_Order += m_Order + x.m_Order; - - return res; - } - - BigFloat operator / (const BigFloat& x) const - { - assert(x.m_Value); // otherwise div-by-zero exc - - uint64_t val = m_Value; - val <<= nBits; - val /= x.m_Value; - - BigFloat res(val); - res.m_Order += m_Order - (x.m_Order + nBits); - return res; - } - - template - BigFloat(const T& x) { *this = x; } - }; - - void Difficulty::Calculate(const Raw& ref, uint32_t dh, uint32_t dtTrg_s, uint32_t dtSrc_s) - { - uint64_t div = dtSrc_s; - div *= dh; - - BigFloat x = BigFloat(ref) * BigFloat(dtTrg_s) / BigFloat(div); - - // to packed. - m_Packed = 0; - - if (x.m_Value) - { - assert(1 & (x.m_Value >> (BigFloat::nBits - 1))); - x.m_Order += (BigFloat::nBits - 1 - s_MantissaBits); - if (x.m_Order >= 0) - { - x.m_Value >>= (BigFloat::nBits - 1 - s_MantissaBits); - Pack(x.m_Order, x.m_Value); - } - } - } - - double Difficulty::ToFloat() const - { - uint32_t order, mantissa; - Unpack(order, mantissa); - - int nOrderCorrected = order - s_MantissaBits; // must be signed - return ldexp(mantissa, nOrderCorrected); - } - - double Difficulty::ToFloat(Raw& x) - { - double res = 0; - - int nOrder = x.nBits - 8 - s_MantissaBits; - for (uint32_t i = 0; i < x.nBytes; i++, nOrder -= 8) - { - uint8_t n = x.m_pData[i]; - if (n) - res += ldexp(n, nOrder); - } - - return res; - } - - std::ostream& operator << (std::ostream& s, const Difficulty& d) - { - typedef uintBig_t uintOrder; - typedef uintBig_t uintMantissa; - - uintOrder n0; - n0.AssignSafe(d.m_Packed >> Difficulty::s_MantissaBits, 0); - char sz0[uintOrder::nTxtLen + 1]; - n0.Print(sz0); - - uintMantissa n1; - n1.AssignSafe(d.m_Packed & ((1U << Difficulty::s_MantissaBits) - 1), 0); - char sz1[uintMantissa::nTxtLen + 1]; - n1.Print(sz1); - - s << sz0 << '-' << sz1 << '(' << d.ToFloat() << ')'; - - return s; - } - -} // namespace beam diff --git a/src/Native/libbeamhash/beam/core/difficulty.h b/src/Native/libbeamhash/beam/core/difficulty.h deleted file mode 100644 index 59fce667be..0000000000 --- a/src/Native/libbeamhash/beam/core/difficulty.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2018 The Beam Team -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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. - -#pragma once -#include "uintBig.h" - -namespace beam -{ - struct Difficulty - { - uint32_t m_Packed; - static const uint32_t s_MantissaBits = 24; - - Difficulty(uint32_t d = 0) :m_Packed(d) {} - - typedef beam::uintBig_t<32> Raw; - - // maximum theoretical difficulty value, which corresponds to 'infinite' (only Zero hash value meet the target). - // Corresponds to 0xffff...fff raw value. - static const uint32_t s_MaxOrder = Raw::nBits - s_MantissaBits - 1; - static const uint32_t s_Inf = (s_MaxOrder + 1) << s_MantissaBits; - - bool IsTargetReached(const beam::uintBig_t<32>&) const; - - void Unpack(Raw&) const; - - void Unpack(uint32_t& order, uint32_t& mantissa) const; - void Pack(uint32_t order, uint32_t mantissa); - - void Calculate(const Raw& wrk, uint32_t dh, uint32_t dtTrg_s, uint32_t dtSrc_s); - - friend Raw operator + (const Raw&, const Difficulty&); - friend Raw operator - (const Raw&, const Difficulty&); - friend Raw& operator += (Raw&, const Difficulty&); - friend Raw& operator -= (Raw&, const Difficulty&); - - double ToFloat() const; - static double ToFloat(Raw&); - - struct BigFloat; - - }; - - std::ostream& operator << (std::ostream&, const Difficulty&); -} diff --git a/src/Native/libbeamhash/beam/core/uintBig.cpp b/src/Native/libbeamhash/beam/core/uintBig.cpp deleted file mode 100644 index 313b7d2d58..0000000000 --- a/src/Native/libbeamhash/beam/core/uintBig.cpp +++ /dev/null @@ -1,346 +0,0 @@ -// Copyright 2018 The Beam Team -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 "uintBig.h" - -namespace beam { - - - char ChFromHex(uint8_t v) - { - return v + ((v < 10) ? '0' : ('a' - 10)); - } - - void uintBigImpl::_Print(const uint8_t* pDst, uint32_t nDst, std::ostream& s) - { - const uint32_t nDigitsMax = 8; - if (nDst > nDigitsMax) - nDst = nDigitsMax; // truncate - - char sz[nDigitsMax * 2 + 1]; - - _Print(pDst, nDst, sz); - s << sz; - } - - void uintBigImpl::_Print(const uint8_t* pDst, uint32_t nDst, char* sz) - { - for (uint32_t i = 0; i < nDst; i++) - { - sz[i * 2] = ChFromHex(pDst[i] >> 4); - sz[i * 2 + 1] = ChFromHex(pDst[i] & 0xf); - } - - sz[nDst << 1] = 0; - } - - void uintBigImpl::_Assign(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc, uint32_t nSrc) - { - if (nSrc >= nDst) - memcpy(pDst, pSrc + nSrc - nDst, nDst); - else - { - memset0(pDst, nDst - nSrc); - memcpy(pDst + nDst - nSrc, pSrc, nSrc); - } - } - - uint8_t uintBigImpl::_Inc(uint8_t* pDst, uint32_t nDst) - { - for (uint32_t i = nDst; i--; ) - if (++pDst[i]) - return 0; - - return 1; - } - - uint8_t uintBigImpl::_Inc(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc) - { - uint16_t carry = 0; - for (uint32_t i = nDst; i--; ) - { - carry += pDst[i]; - carry += pSrc[i]; - - pDst[i] = (uint8_t) carry; - carry >>= 8; - } - - return (uint8_t) carry; - } - - uint8_t uintBigImpl::_Inc(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc, uint32_t nSrc) - { - if (nDst <= nSrc) - return _Inc(pDst, nDst, pSrc + nSrc - nDst); // src is at least our size - - if (!_Inc(pDst + nDst - nSrc, nSrc, pSrc)) - return 0; - - // propagete carry - return _Inc(pDst, nDst - nSrc); - } - - void uintBigImpl::_Inv(uint8_t* pDst, uint32_t nDst) - { - for (uint32_t i = nDst; i--; ) - pDst[i] ^= 0xff; - } - - void uintBigImpl::_Xor(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc) - { - for (uint32_t i = nDst; i--; ) - pDst[i] ^= pSrc[i]; - } - - void uintBigImpl::_Xor(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc, uint32_t nSrc) - { - if (nDst <= nSrc) - _Xor(pDst, nDst, pSrc + nSrc - nDst); // src is at least our size - else - _Xor(pDst + nDst - nSrc, nSrc, pSrc); - } - - void uintBigImpl::_Mul(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc0, uint32_t nSrc0, const uint8_t* pSrc1, uint32_t nSrc1) - { - memset0(pDst, nDst); - - if (nSrc0 > nDst) - { - pSrc0 += nSrc0 - nDst; - nSrc0 = nDst; - } - - if (nSrc1 > nDst) - { - pSrc1 += nSrc1 - nDst; - nSrc1 = nDst; - } - - int32_t nDelta = nSrc0 + nSrc1 - nDst - 1; - - for (uint32_t i0 = nSrc0; i0--; ) - { - uint8_t x0 = pSrc0[i0]; - uint16_t carry = 0; - - uint32_t iDst = i0 - nDelta; // don't care if overflows - uint32_t i1Min = (iDst > nDst) ? (-static_cast(iDst)) : 0; - for (uint32_t i1 = nSrc1; i1-- > i1Min; ) - { - uint8_t& dst = pDst[iDst + i1]; - - uint16_t x1 = pSrc1[i1]; - x1 *= x0; - carry += x1; - carry += dst; - - dst = (uint8_t) carry; - carry >>= 8; - } - - if (iDst <= nDst) - while (carry && iDst--) - { - uint8_t& dst = pDst[iDst]; - carry += dst; - - dst = (uint8_t) carry; - carry >>= 8; - } - } - } - - int uintBigImpl::_Cmp(const uint8_t* pSrc0, uint32_t nSrc0, const uint8_t* pSrc1, uint32_t nSrc1) - { - if (nSrc0 > nSrc1) - { - uint32_t diff = nSrc0 - nSrc1; - if (!memis0(pSrc0, diff)) - return 1; - - pSrc0 += diff; - nSrc0 = nSrc1; - } else - if (nSrc0 < nSrc1) - { - uint32_t diff = nSrc1 - nSrc0; - if (!memis0(pSrc1, diff)) - return -1; - - pSrc1 += diff; - } - - return memcmp(pSrc0, pSrc1, nSrc0); - } - - uint32_t uintBigImpl::_GetOrder(const uint8_t* pDst, uint32_t nDst) - { - for (uint32_t nByte = 0; ; nByte++) - { - if (nDst == nByte) - return 0; // the number is zero - - uint8_t x = pDst[nByte]; - if (!x) - continue; - - uint32_t nOrder = ((nDst - nByte) << 3) - 7; - while (x >>= 1) - nOrder++; - - return nOrder; - } - - } - - bool uintBigImpl::_Accept(uint8_t* pDst, const uint8_t* pThr, uint32_t nDst, uint32_t nThrOrder) - { - if (!nThrOrder) - return false; - - nThrOrder--; - uint32_t nOffs = nDst - 1 - (nThrOrder >> 3); - uint8_t msk = uint8_t(2 << (7 & nThrOrder)) - 1; - assert(msk); - - pDst[nOffs] &= msk; - - if (memcmp(pDst + nOffs, pThr + nOffs, nDst - nOffs) >= 0) - return false; - - memset0(pDst, nOffs); - return true; - } - - FourCC::Text::Text(uint32_t n) - { - reinterpret_cast::Type&>(m_sz) = n; // convertion - m_sz[_countof(m_sz) - 1] = 0; - - // fix illegal chars - for (size_t i = 0; i < _countof(m_sz) - 1; i++) - { - char& c = m_sz[i]; - if ((c < ' ') || (c > '~')) - c = ' '; - } - } - - std::ostream& operator << (std::ostream& s, const FourCC& x) - { - s << FourCC::Text(x); - return s; - } - - std::ostream& operator << (std::ostream& s, const FourCC::Text& x) - { - s << x.m_sz; - return s; - } - - void uintBigImpl::_ShiftRight(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc, uint32_t nSrc, uint32_t nBits) - { - // assuming pDst and pSrc may be the same - - uint32_t nBytes = nBits >> 3; - if (nBytes >= nSrc) - nSrc = nBits = 0; - else - { - nSrc -= nBytes; - nBits &= 7; - } - - uint8_t* pDst0 = pDst; - - if (nDst > nSrc) - { - pDst += nDst - nSrc; - nDst = nSrc; - } - else - pSrc += nSrc - nDst; - - if (nBits) - { - uint32_t nLShift = 8 - nBits; - - for (uint32_t i = nDst; i--; ) - { - // pSrc and pDst may be the same - pDst[i] = pSrc[i] >> nBits; - if (nSrc + i > nDst) - pDst[i] |= (pSrc[int32_t(i - 1)] << nLShift); - } - } - else - memmove(pDst, pSrc, nDst); - - memset0(pDst0, pDst - pDst0); - } - - void uintBigImpl::_ShiftLeft(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc, uint32_t nSrc, uint32_t nBits) - { - // assuming pDst and pSrc may be the same - - uint32_t nBytes = nBits >> 3; - if (nBytes >= nDst) - { - nBytes = nDst; - nDst = nBits = 0; - } - else - { - nBits &= 7; - nDst -= nBytes; - } - - uint8_t* pDst0 = pDst; - - if (nSrc > nDst) - { - pSrc += nSrc - nDst; - nSrc = nDst; - } - else - { - memset0(pDst, nDst - nSrc); - pDst += nDst - nSrc; - } - - if (nBits) - { - if (nSrc) - { - uint32_t nRShift = 8 - nBits; - - if (nDst > nSrc) - pDst[-1] = pSrc[0] >> nRShift; - - for (size_t i = 0; i < nSrc; i++) - { - pDst[i] = pSrc[i] << nBits; - if (i + 1 < nSrc) - pDst[i] |= pSrc[i + 1] >> nRShift; - } - } - } - else - memmove(pDst, pSrc, nSrc); - - memset0(pDst0 + nDst, nBytes); - } - -} // namespace beam diff --git a/src/Native/libbeamhash/beam/core/uintBig.h b/src/Native/libbeamhash/beam/core/uintBig.h deleted file mode 100644 index 9492e88c14..0000000000 --- a/src/Native/libbeamhash/beam/core/uintBig.h +++ /dev/null @@ -1,360 +0,0 @@ -// Copyright 2018 The Beam Team -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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. - -#pragma once -#include "common.h" - -namespace beam -{ - // Syntactic sugar! - enum Zero_ { Zero }; - - // Simple arithmetics. For casual use only (not performance-critical) - - class uintBigImpl { - protected: - void _Assign(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc, uint32_t nSrc); - - // all those return carry (exceeding byte) - static uint8_t _Inc(uint8_t* pDst, uint32_t nDst); - static uint8_t _Inc(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc); - static uint8_t _Inc(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc, uint32_t nSrc); - - static void _Inv(uint8_t* pDst, uint32_t nDst); - static void _Xor(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc); - static void _Xor(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc, uint32_t nSrc); - - static void _Mul(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc0, uint32_t nSrc0, const uint8_t* pSrc1, uint32_t nSrc1); - static int _Cmp(const uint8_t* pSrc0, uint32_t nSrc0, const uint8_t* pSrc1, uint32_t nSrc1); - static void _Print(const uint8_t* pDst, uint32_t nDst, std::ostream&); - static void _Print(const uint8_t* pDst, uint32_t nDst, char*); - - static uint32_t _GetOrder(const uint8_t* pDst, uint32_t nDst); - static bool _Accept(uint8_t* pDst, const uint8_t* pThr, uint32_t nDst, uint32_t nThrOrder); - - template - static void _AssignRangeAligned(uint8_t* pDst, uint32_t nDst, T x, uint32_t nOffsetBytes, uint32_t nBytesX) - { - static_assert(T(-1) > 0, "must be unsigned"); - - assert(nDst >= nBytesX + nOffsetBytes); - nDst -= (nOffsetBytes + nBytesX); - - for (uint32_t i = nBytesX; i--; x >>= 8) - pDst[nDst + i] = (uint8_t) x; - } - - template - static bool _AssignRangeAlignedSafe(uint8_t* pDst, uint32_t nDst, T x, uint32_t nOffsetBytes, uint32_t nBytesX) // returns false if truncated - { - if (nDst < nOffsetBytes) - return false; - - uint32_t n = nDst - nOffsetBytes; - bool b = (nBytesX <= n); - - _AssignRangeAligned(pDst, nDst, x, nOffsetBytes, b ? nBytesX : n); - return b; - } - - template - static bool _AssignSafe(uint8_t* pDst, uint32_t nDst, T x, uint32_t nOffset) // returns false if truncated - { - uint32_t nOffsetBytes = nOffset >> 3; - nOffset &= 7; - - if (!_AssignRangeAlignedSafe(pDst, nDst, x << nOffset, nOffsetBytes, sizeof(x))) - return false; - - if (nOffset) - { - nOffsetBytes += sizeof(x); - if (nDst - 1 < nOffsetBytes) - return false; - - uint8_t resid = uint8_t(x >> ((sizeof(x) << 3) - nOffset)); - pDst[nDst - 1 - nOffsetBytes] = resid; - } - - return true; - } - - template - static void _ExportAligned(T& out, const uint8_t* pDst, uint32_t nDst) - { - static_assert(T(-1) > 0, "must be unsigned"); - - out = pDst[0]; - for (uint32_t i = 1; i < nDst; i++) - out = (out << 8) | pDst[i]; - } - - static void _ShiftRight(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc, uint32_t nSrc, uint32_t nBits); - static void _ShiftLeft(uint8_t* pDst, uint32_t nDst, const uint8_t* pSrc, uint32_t nSrc, uint32_t nBits); - - }; - - template - struct uintBig_t - :public uintBigImpl - { - static const uint32_t nBits = nBytes_ << 3; - static const uint32_t nBytes = nBytes_; - - uintBig_t() - { -#ifdef _DEBUG - memset(m_pData, 0xcd, nBytes); -#endif // _DEBUG - } - - uintBig_t(Zero_) - { - ZeroObject(m_pData); - } - - uintBig_t(const uint8_t p[nBytes]) - { - memcpy(m_pData, p, nBytes); - } - - uintBig_t(const std::initializer_list& v) - { - _Assign(m_pData, nBytes, v.begin(), static_cast(v.size())); - } - - uintBig_t(const Blob& v) - { - operator = (v); - } - - template - uintBig_t(T x) - { - AssignOrdinal(x); - } - - // in Big-Endian representation - uint8_t m_pData[nBytes]; - - uintBig_t& operator = (Zero_) - { - ZeroObject(m_pData); - return *this; - } - - template - uintBig_t& operator = (const uintBig_t& v) - { - _Assign(m_pData, nBytes, v.m_pData, v.nBytes); - return *this; - } - - uintBig_t& operator = (const Blob& v) - { - _Assign(m_pData, nBytes, static_cast(v.p), v.n); - return *this; - } - - bool operator == (Zero_) const - { - return memis0(m_pData, nBytes); - } - - template - void AssignOrdinal(T x) - { - memset0(m_pData, nBytes - sizeof(x)); - AssignRange(x); - } - - // from ordinal types (unsigned) - template - uintBig_t& operator = (T x) - { - AssignOrdinal(x); - return *this; - } - - template - void Export(T& x) const - { - static_assert(sizeof(T) >= nBytes, ""); - _ExportAligned(x, m_pData, nBytes); - } - - template - void ExportWord(T& x) const - { - static_assert(sizeof(T) * (iWord + 1) <= nBytes, ""); - _ExportAligned(x, m_pData + sizeof(T) * iWord, sizeof(T)); - } - - template - void AssignRange(T x) - { - static_assert(!(nOffset & 7), "offset must be on byte boundary"); - static_assert(nBytes >= sizeof(x) + (nOffset >> 3), "too small"); - - _AssignRangeAligned(m_pData, nBytes, x, nOffset >> 3, sizeof(x)); - } - - template - bool AssignSafe(T x, uint32_t nOffset) // returns false if truncated - { - return _AssignSafe(m_pData, nBytes, x, nOffset); - } - - void Inc() - { - _Inc(m_pData, nBytes); - } - - template - void operator += (const uintBig_t& x) - { - _Inc(m_pData, nBytes, x.m_pData, x.nBytes); - } - - template - void AssignMul(const uintBig_t& x0, const uintBig_t & x1) - { - _Mul(m_pData, nBytes, x0.m_pData, x0.nBytes, x1.m_pData, x1.nBytes); - } - - template - uintBig_t operator * (const uintBig_t& x) const - { - uintBig_t res; - res.AssignMul(*this, x); - return res; - } - - void Inv() - { - _Inv(m_pData, nBytes); - } - - void Negate() - { - Inv(); - Inc(); - } - - template - void operator ^= (const uintBig_t& x) - { - _Xor(m_pData, nBytes, x.m_pData, x.nBytes); - } - - template - int cmp(const uintBig_t& x) const - { - return _Cmp(m_pData, nBytes, x.m_pData, x.nBytes); - } - - uint32_t get_Order() const - { - // how much the number should be shifted to reach zero. - // returns 0 iff the number is already zero. - return _GetOrder(m_pData, nBytes); - } - - template - void ShiftRight(uint32_t nBits, uintBig_t& res) const - { - _ShiftRight(res.m_pData, res.nBytes, m_pData, nBytes, nBits); - } - - template - void ShiftLeft(uint32_t nBits, uintBig_t& res) const - { - _ShiftLeft(res.m_pData, res.nBytes, m_pData, nBytes, nBits); - } - - // helper, for uniform random generation within specific bounds - struct Threshold - { - const uintBig_t& m_Val; - uint32_t m_Order; - - Threshold(const uintBig_t& val) - :m_Val(val) - { - m_Order = val.get_Order(); - } - - operator bool() const { return m_Order > 0; } - - bool Accept(uintBig_t& dst) const - { - return _Accept(dst.m_pData, m_Val.m_pData, nBytes, m_Order); - } - }; - - COMPARISON_VIA_CMP - - static const uint32_t nTxtLen = nBytes * 2; // not including 0-term - - void Print(char* sz) const - { - _Print(m_pData, nBytes, sz); - } - - friend std::ostream& operator << (std::ostream& s, const uintBig_t& x) - { - _Print(x.m_pData, x.nBytes, s); - return s; - } - }; - - template - struct uintBigFor { - typedef uintBig_t Type; - }; - - template - inline typename uintBigFor::Type uintBigFrom(T x) { - return typename uintBigFor::Type(x); - } - - struct FourCC - { - uint32_t V; // In "host" order, i.e. platform-dependent - operator uint32_t () const { return V; } - - FourCC() {} - FourCC(uint32_t x) :V(x) {} - - struct Text - { - char m_sz[sizeof(uint32_t) + 1]; - Text(uint32_t); - operator const char* () const { return m_sz; } - }; - - template - struct Const { - static const uint32_t V = (((((a << 8) | b) << 8) | c) << 8) | d; - }; - - }; - - std::ostream& operator << (std::ostream& s, const FourCC::Text& x); - std::ostream& operator << (std::ostream& s, const FourCC& x); - -#define ARRAY_ELEMENT_SAFE(arr, index) ((arr)[(((index) < _countof(arr)) ? (index) : (_countof(arr) - 1))]) -#define FOURCC_FROM(name) beam::FourCC::Const::V - -} // namespace beam diff --git a/src/Native/libbeamhash/beam/utility/common.cpp b/src/Native/libbeamhash/beam/utility/common.cpp deleted file mode 100644 index d56e579e87..0000000000 --- a/src/Native/libbeamhash/beam/utility/common.cpp +++ /dev/null @@ -1,461 +0,0 @@ -// Copyright 2018 The Beam Team -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 "common.h" -#include - -#ifndef WIN32 -# include -# include -#else -# include -# pragma comment (lib, "dbghelp") -#endif // WIN32 - -// misc -bool memis0(const void* p, size_t n) -{ - for (size_t i = 0; i < n; i++) - if (((const uint8_t*)p)[i]) - return false; - return true; -} - -void memxor(uint8_t* pDst, const uint8_t* pSrc, size_t n) -{ - for (size_t i = 0; i < n; i++) - pDst[i] ^= pSrc[i]; -} - -namespace beam -{ - -#ifdef WIN32 - - std::wstring Utf8toUtf16(const char* sz) - { - std::wstring sRet; - - int nVal = MultiByteToWideChar(CP_UTF8, 0, sz, -1, NULL, 0); - if (nVal > 1) - { - sRet.resize(nVal - 1); - MultiByteToWideChar(CP_UTF8, 0, sz, -1, &sRet[0], nVal); - } - - return sRet; - } - - bool DeleteFile(const char* sz) - { - return ::DeleteFileW(Utf8toUtf16(sz).c_str()) != FALSE; - } - -#else // WIN32 - - bool DeleteFile(const char* sz) - { - return !unlink(sz); - } - - -#endif // WIN32 - - Blob::Blob(const ByteBuffer& bb) - { - if ((n = (uint32_t)bb.size()) != 0) - p = &bb.at(0); - } - - void Blob::Export(ByteBuffer& x) const - { - if (n) - { - x.resize(n); - memcpy(&x.at(0), p, n); - } - else - x.clear(); - } -} - -namespace std -{ - void ThrowLastError() - { -#ifdef WIN32 - ThrowSystemError(GetLastError()); -#else // WIN32 - ThrowSystemError(errno); -#endif // WIN32 - } - - void ThrowSystemError(int nErrorCode) - { - char sz[0x20]; - snprintf(sz, _countof(sz), "System Error=%d", nErrorCode); - throw runtime_error(sz); - } - - void TestNoError(const ios& obj) - { - if (obj.fail()) - ThrowLastError(); - } - - FStream::FStream() - :m_Remaining(0) - { - } - - bool FStream::Open(const char* sz, bool bRead, bool bStrict /* = false */, bool bAppend /* = false */) - { - m_Remaining = 0; - - int mode = ios_base::binary; - mode |= bRead ? ios_base::ate : bAppend ? ios_base::app : ios_base::trunc; - mode |= bRead ? ios_base::in : ios_base::out; - -#ifdef WIN32 - std::wstring sPathArg = beam::Utf8toUtf16(sz); -#else // WIN32 - const char* sPathArg = sz; -#endif // WIN32 - - m_F.open(sPathArg, (ios_base::openmode) mode); - - if (m_F.fail()) - { - if (bStrict) - ThrowLastError(); - return false; - } - - if (bRead) - { - m_Remaining = m_F.tellg(); - m_F.seekg(0); - } - - return true; - } - - void FStream::Close() - { - if (m_F.is_open()) - { - m_F.close(); - m_Remaining = 0; - } - } - - void FStream::Restart() - { - m_Remaining += m_F.tellg(); - m_F.seekg(0); - } - - void FStream::Seek(uint64_t n) - { - m_Remaining += m_F.tellg(); - m_F.seekg(n); - m_Remaining -= m_F.tellg(); - } - - void FStream::NotImpl() - { - throw runtime_error("not impl"); - } - - size_t FStream::read(void* pPtr, size_t nSize) - { - m_F.read((char*)pPtr, nSize); - size_t ret = m_F.gcount(); - m_Remaining -= ret; - - if (ret != nSize) - throw runtime_error("underflow"); - - return ret; - } - - size_t FStream::write(const void* pPtr, size_t nSize) - { - m_F.write((char*) pPtr, nSize); - TestNoError(m_F); - - return nSize; - } - - char FStream::getch() - { - char ch; - read(&ch, 1); - return ch; - } - - char FStream::peekch() const - { - NotImpl(); -#if !(defined(_MSC_VER) && defined(NDEBUG)) - return 0; -#endif - } - - void FStream::ungetch(char) - { - NotImpl(); - } - - void FStream::Flush() - { - m_F.flush(); - TestNoError(m_F); - } - -} // namespace std - -#if defined(BEAM_USE_STATIC) - -#if defined(_MSC_VER) && (_MSC_VER >= 1900) - -FILE _iob[] = { *stdin, *stdout, *stderr }; -extern "C" FILE * __cdecl __iob_func(void) { return _iob; } - -#endif - -#endif - -#ifdef WIN32 - -wchar_t g_szDumpPathTemplate[MAX_PATH]; -uint32_t g_DumpIdx = 0; - -void MiniDumpWriteGuarded(EXCEPTION_POINTERS* pExc) -{ - HANDLE hFile; - - wchar_t szPath[MAX_PATH]; - for ( ; ; g_DumpIdx++) - { - _snwprintf_s(szPath, _countof(szPath), _countof(szPath), L"%s%u.dmp", g_szDumpPathTemplate, g_DumpIdx); - szPath[_countof(szPath) - 1] = 0; // for more safety - - hFile = CreateFileW(szPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); - if (INVALID_HANDLE_VALUE != hFile) - break; // ok - - if (GetLastError() != ERROR_FILE_EXISTS) - return; // oops! - } - - MINIDUMP_EXCEPTION_INFORMATION mdei = { 0 }; - mdei.ThreadId = GetCurrentThreadId(); - mdei.ExceptionPointers = pExc; - - MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, NULL, NULL); - - verify(CloseHandle(hFile)); - -} - -void MiniDumpWriteWrap(EXCEPTION_POINTERS* pExc) -{ - __try { - MiniDumpWriteGuarded(pExc); - } __except (EXCEPTION_EXECUTE_HANDLER) { - } -} - - -void RaiseCustumExc() -{ - RaiseException(0xC20A1000, EXCEPTION_NONCONTINUABLE, 0, NULL); -} - -void MiniDumpWriteNoExc() -{ - __try { - RaiseCustumExc(); - } __except (MiniDumpWriteGuarded(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) { - } -} - -DWORD WINAPI MiniDumpWriteInThread(PVOID pPtr) -{ - MiniDumpWriteWrap((EXCEPTION_POINTERS*) pPtr); - return 0; -} - -long WINAPI ExcFilter(EXCEPTION_POINTERS* pExc) -{ - switch (pExc->ExceptionRecord->ExceptionCode) - { - case STATUS_STACK_OVERFLOW: - { - DWORD dwThreadID; - HANDLE hThread = CreateThread(NULL, 0, MiniDumpWriteInThread, pExc, 0, &dwThreadID); - if (hThread) - { - WaitForSingleObject(hThread, INFINITE); - CloseHandle(hThread); - } - } - break; - - default: - MiniDumpWriteWrap(pExc); - } - return EXCEPTION_CONTINUE_SEARCH; -} - -//void CrtInvHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved) -//{ -// if (IsDebuggerPresent()) -// /*_invalid_parameter_handler(expression, function, file, line, pReserved)*/; -// else -// MiniDumpWriteNoExc(); -//} - -terminate_function g_pfnTerminate = NULL; - -void TerminateHandler() -{ - MiniDumpWriteNoExc(); - g_pfnTerminate(); -} - -//_CRT_REPORT_HOOK g_pfnCrtReport = NULL; - -int CrtReportHook(int n, char* sz, int* p) -{ - MiniDumpWriteNoExc(); - return 0; -} - -void PureCallHandler() -{ - RaiseCustumExc(); // convert it to regular exc -} - -void beam::Crash::InstallHandler(const char* szLocation) -{ - if (szLocation) - { - std::wstring s = beam::Utf8toUtf16(szLocation); - size_t nLen = s.size(); - if (nLen >= _countof(g_szDumpPathTemplate)) - nLen = _countof(g_szDumpPathTemplate) - 1; - - memcpy(g_szDumpPathTemplate, s.c_str(), sizeof(wchar_t) * (nLen + 1)); - } - else - { - GetModuleFileNameW(NULL, g_szDumpPathTemplate, _countof(g_szDumpPathTemplate)); - g_szDumpPathTemplate[_countof(g_szDumpPathTemplate) - 1] = 0; - } - - SetUnhandledExceptionFilter(ExcFilter); - - // CRT-specific - //_set_invalid_parameter_handler(CrtInvHandler); - g_pfnTerminate = set_terminate(TerminateHandler); - _CrtSetReportHook(CrtReportHook); - _set_purecall_handler(PureCallHandler); -} - -#else // WIN32 - -void beam::Crash::InstallHandler(const char*) -{ -} - -#endif // WIN32 - -void beam::Crash::Induce(Type type) -{ - switch (type) - { - case StlInvalid: - // will invoke handler in checked version. Otherwise will just crash normally - { - std::vector vv; - vv[4] = 0; - } - break; - - case StackOverflow: - { - struct StackOverflow - { - // this is tricky: we need to prevent optimization of the buffer, and confuse the compiler and convience it that this code "might" work - uint8_t m_pArr[0x400]; - uint8_t Do(uint8_t n) - { - m_pArr[0] = n ^ 1; - - if (n) - { - StackOverflow v; - v.Do(n ^ 1); - memxor(m_pArr, v.m_pArr, sizeof(m_pArr)); - } - - for (size_t i = 0; i < _countof(m_pArr); i++) - n ^= m_pArr[i]; - - return n; - } - }; - - StackOverflow v; - size_t val = v.Do(7); - - // make sure the retval is really needed, though this code shouldn't be reached - volatile int* p = reinterpret_cast(val); - *p = 0; - - } - break; - - case PureCall: - { - struct Base { - Base* m_pOther; - - ~Base() { - m_pOther->Func(); - } - - virtual void Func() = 0; - }; - - struct Derived :public Base { - virtual void Func() override {} - }; - - Derived d; - d.m_pOther = &d; - } - break; - - case Terminate: - std::terminate(); - break; - - default: - // default crash - *reinterpret_cast(0x48) = 15; - } -} diff --git a/src/Native/libbeamhash/beam/utility/common.h b/src/Native/libbeamhash/beam/utility/common.h deleted file mode 100644 index 34083724c8..0000000000 --- a/src/Native/libbeamhash/beam/utility/common.h +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright 2018 The Beam Team -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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. - -#pragma once - -#include - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdelete-non-virtual-dtor" -#endif - -#include - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // memcmp -#include - -#ifdef WIN32 -# include -#endif // WIN32 - -#ifndef verify -# ifdef NDEBUG -# define verify(x) ((void)(x)) -# else // NDEBUG -# define verify(x) assert(x) -# endif // NDEBUG -#endif // verify - -#define IMPLEMENT_GET_PARENT_OBJ(parent_class, this_var) \ - parent_class& get_ParentObj() const { \ - parent_class* p = (parent_class*) (((uint8_t*) this) + 1 - (uint8_t*) (&((parent_class*) 1)->this_var)); \ - assert(this == &p->this_var); /* this also tests that the variable of the correct type */ \ - return *p; \ - } - -#ifndef _countof -# define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) -#endif // _countof - -inline void memset0(void* p, size_t n) { memset(p, 0, n); } -bool memis0(const void* p, size_t n); -void memxor(uint8_t* pDst, const uint8_t* pSrc, size_t n); - - -template -inline void ZeroObject(T& x) -{ - memset0(&x, sizeof(x)); -} - -#define COMPARISON_VIA_CMP \ - template bool operator < (const T& x) const { return cmp(x) < 0; } \ - template bool operator > (const T& x) const { return cmp(x) > 0; } \ - template bool operator <= (const T& x) const { return cmp(x) <= 0; } \ - template bool operator >= (const T& x) const { return cmp(x) >= 0; } \ - template bool operator == (const T& x) const { return cmp(x) == 0; } \ - template bool operator != (const T& x) const { return cmp(x) != 0; } - - -namespace Cast -{ - template inline T& NotConst(const T& x) { return (T&) x; } - template inline T* NotConst(const T* p) { return (T*) p; } - - template inline const TT& Up(const T& x) - { - const TT& ret = (const TT&) x; - const T& unused = ret; unused; - return ret; - } - - template inline TT& Up(T& x) - { - TT& ret = (TT&) x; - T& unused = ret; unused; - return ret; - } - - template inline TT* Up(T* p) - { - TT* ret = (TT*) p; - T* unused = ret; unused; - return ret; - } - - template inline const TT* Up(const T* p) - { - const TT* ret = (const TT*) p; - const T* unused = ret; unused; - return ret; - } - - template inline TT& Down(T& x) - { - return x; - } - - template inline const TT& Down(const T& x) - { - return x; - } -} // namespace Cast - - - -namespace beam -{ - typedef uint64_t Timestamp; - typedef uint64_t Height; - typedef uint64_t Amount; - typedef std::vector ByteBuffer; - - template - struct uintBig_t; - -#ifdef WIN32 - std::wstring Utf8toUtf16(const char*); -#endif // WIN32 - - bool DeleteFile(const char*); - - struct Blob { - const void* p; - uint32_t n; - - Blob() {} - Blob(const void* p_, uint32_t n_) :p(p_), n(n_) {} - Blob(const ByteBuffer& bb); - - template - Blob(const uintBig_t& x) :p(x.m_pData), n(x.nBytes) {} - - void Export(ByteBuffer&) const; - }; - - template - struct TemporarySwap - { - T& m_var0; - T& m_var1; - - TemporarySwap(T& v0, T& v1) - :m_var0(v0) - ,m_var1(v1) - { - std::swap(m_var0, m_var1); // std::swap has specializations for many types that have internal swap(), such as unique_ptr, shared_ptr - } - - ~TemporarySwap() - { - std::swap(m_var0, m_var1); - } - }; - - namespace Crash - { - void InstallHandler(const char* szLocation); - - enum Type { - - BadPtr, - StlInvalid, - StackOverflow, - PureCall, - Terminate, - - count - }; - - void Induce(Type); - } -} - -namespace std -{ - void ThrowLastError(); - void TestNoError(const ios& obj); - void ThrowSystemError(int); - - // wrapper for std::fstream, with semantics suitable for serialization - class FStream - { - std::fstream m_F; - uint64_t m_Remaining; // used in read-stream, to indicate the EOF before trying to deserialize something - - static void NotImpl(); - - public: - FStream(); - bool Open(const char*, bool bRead, bool bStrict = false, bool bAppend = false); // strict - throw exc if error - bool IsOpen() const { return m_F.is_open(); } - void Close(); - uint64_t get_Remaining() const { return m_Remaining; } - - void Restart(); // for read-stream - jump to the beginning of the file - void Seek(uint64_t); - uint64_t Tell() { return m_F.tellg(); } - - // read/write always return the size requested. Exception is thrown if underflow or error - size_t read(void* pPtr, size_t nSize); - size_t write(const void* pPtr, size_t nSize); - void Flush(); - - char getch(); - char peekch() const; - void ungetch(char); - }; -} diff --git a/src/Native/libbeamhash/beamHashIII.h b/src/Native/libbeamhash/beamHashIII.h new file mode 100644 index 0000000000..c115751c9a --- /dev/null +++ b/src/Native/libbeamhash/beamHashIII.h @@ -0,0 +1,56 @@ +// Copyright (c) 2020 The Beam Team + +#ifndef BEAMHASH_H +#define BEAMHASH_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "powScheme.h" + +const uint32_t workBitSize = 448; +const uint32_t collisionBitSize = 24; +const uint32_t numRounds = 5; + +class stepElem +{ + friend class BeamHash_III; + +private: + std::bitset workBits; + std::vector indexTree; + +public: + stepElem(const uint64_t* prePow, uint32_t index); + stepElem(const stepElem& a, const stepElem& b, uint32_t remLen); + + void applyMix(uint32_t remLen); + uint32_t getCollisionBits() const; + bool isZero(); + + friend bool hasCollision(stepElem& a, stepElem& b); + friend bool distinctIndices(stepElem& a, stepElem& b); + friend bool indexAfter(stepElem& a, stepElem& b); + friend uint64_t getLowBits(stepElem test); +}; + +class BeamHash_III : public PoWScheme +{ +public: + int InitialiseState(blake2b_state& base_state); + bool IsValidSolution(const blake2b_state& base_state, std::vector soln); + + + bool OptimisedSolve(const blake2b_state& base_state, + const std::function&)> validBlock, + const std::function cancelled); +}; + +#endif \ No newline at end of file diff --git a/src/Native/libbeamhash/beamHashIII_imp.cpp b/src/Native/libbeamhash/beamHashIII_imp.cpp new file mode 100644 index 0000000000..5c1b4fde7e --- /dev/null +++ b/src/Native/libbeamhash/beamHashIII_imp.cpp @@ -0,0 +1,448 @@ + +#include "beamHashIII.h" + + +namespace sipHash +{ + +static uint64_t rotl(uint64_t x, uint64_t b) +{ + return (x << b) | (x >> (64 - b)); +} + +#define sipRound() \ + { \ + v0 += v1; \ + v2 += v3; \ + v1 = rotl(v1, 13); \ + v3 = rotl(v3, 16); \ + v1 ^= v0; \ + v3 ^= v2; \ + v0 = rotl(v0, 32); \ + v2 += v1; \ + v0 += v3; \ + v1 = rotl(v1, 17); \ + v3 = rotl(v3, 21); \ + v1 ^= v2; \ + v3 ^= v0; \ + v2 = rotl(v2, 32); \ + } + +uint64_t siphash24(uint64_t state0, uint64_t state1, uint64_t state2, uint64_t state3, uint64_t nonce) +{ + uint64_t v0, v1, v2, v3; + + v0 = state0; + v1 = state1; + v2 = state2; + v3 = state3; + v3 ^= nonce; + sipRound(); + sipRound(); + v0 ^= nonce; + v2 ^= 0xff; + sipRound(); + sipRound(); + sipRound(); + sipRound(); + + return (v0 ^ v1 ^ v2 ^ v3); +} + +} // end namespace sipHash + + +stepElem::stepElem(const uint64_t* prePow, uint32_t index) +{ + workBits.reset(); + + for (int32_t i = 6; i >= 0; i--) + { + workBits = (workBits << 64); + uint64_t hash = sipHash::siphash24(prePow[0], prePow[1], prePow[2], prePow[3], (index << 3) + i); + workBits |= hash; + } + + indexTree.assign(1, index); +} + +stepElem::stepElem(const stepElem& a, const stepElem& b, uint32_t remLen) +{ + // Create a new rounds step element from matching two ancestors + workBits.reset(); + + workBits = a.workBits ^ b.workBits; + workBits = (workBits >> collisionBitSize); + + std::bitset mask; + mask.set(); + mask = (mask >> (workBitSize - remLen)); + workBits &= mask; + + if (a.indexTree[0] < b.indexTree[0]) + { + indexTree.insert(indexTree.end(), a.indexTree.begin(), a.indexTree.end()); + indexTree.insert(indexTree.end(), b.indexTree.begin(), b.indexTree.end()); + } + else + { + indexTree.insert(indexTree.end(), b.indexTree.begin(), b.indexTree.end()); + indexTree.insert(indexTree.end(), a.indexTree.begin(), a.indexTree.end()); + } +} + +void stepElem::applyMix(uint32_t remLen) +{ + std::bitset<512> tempBits(workBits.to_string()); + + // Add in the bits of the index tree to the end of work bits + uint32_t padNum = ((512 - remLen) + collisionBitSize) / (collisionBitSize + 1); + padNum = std::min(padNum, static_cast(indexTree.size())); + + for (uint32_t i = 0; i < padNum; i++) + { + std::bitset<512> tmp(indexTree[i]); + tmp = tmp << (remLen + i * (collisionBitSize + 1)); + tempBits |= tmp; + } + + + // Applyin the mix from the lined up bits + std::bitset<512> mask(0xFFFFFFFFFFFFFFFFUL); + uint64_t result = 0; + for (uint32_t i = 0; i < 8; i++) + { + uint64_t tmp = (tempBits & mask).to_ullong(); + tempBits = tempBits >> 64; + + result += sipHash::rotl(tmp, (29 * (i + 1)) & 0x3F); + } + result = sipHash::rotl(result, 24); + + + // Wipe out lowest 64 bits in favor of the mixed bits + workBits = (workBits >> 64); + workBits = (workBits << 64); + workBits |= std::bitset(result); +} + +uint32_t stepElem::getCollisionBits() const +{ + std::bitset mask((1 << collisionBitSize) - 1); + return (uint32_t)(workBits & mask).to_ullong(); +} + +bool stepElem::isZero() +{ + return workBits.none(); +} + +uint64_t getLowBits(stepElem test) +{ + std::bitset mask(~0ULL); + return (uint64_t)(test.workBits & mask).to_ullong(); +} +/******** + + Friend Functions to compare step elements + +********/ + + +bool hasCollision(stepElem& a, stepElem& b) +{ + return (a.getCollisionBits() == b.getCollisionBits()); +} + +bool distinctIndices(stepElem& a, stepElem& b) +{ + for (uint32_t indexA : a.indexTree) + { + for (uint32_t indexB : b.indexTree) + { + if (indexA == indexB) + return false; + } + } + return true; +} + +bool indexAfter(stepElem& a, stepElem& b) +{ + return (a.indexTree[0] < b.indexTree[0]); +} + +bool sortStepElement(const stepElem& a, const stepElem& b) +{ + return (a.getCollisionBits() < b.getCollisionBits()); +} + + +/******** + + Beam Hash III Verify Functions & CPU Miner + +********/ + +std::vector GetIndicesFromMinimal(std::vector soln) +{ + std::bitset<800> inStream; + std::bitset<800> mask((1 << (collisionBitSize + 1)) - 1); + + inStream.reset(); + for (int32_t i = 99; i >= 0; i--) + { + inStream = (inStream << 8); + inStream |= (uint64_t)soln[i]; + } + + std::vector res; + for (uint32_t i = 0; i < 32; i++) + { + res.push_back((uint32_t)(inStream & mask).to_ullong()); + inStream = (inStream >> (collisionBitSize + 1)); + } + + return res; +} + +std::vector GetMinimalFromIndices(std::vector sol) +{ + std::bitset<800> inStream; + std::bitset<800> mask(0xFF); + + inStream.reset(); + for (int32_t i = static_cast(sol.size()); i >= 0; i--) + { + inStream = (inStream << (collisionBitSize + 1)); + inStream |= (uint64_t)sol[i]; + } + + std::vector res; + for (uint32_t i = 0; i < 100; i++) + { + res.push_back((uint8_t)(inStream & mask).to_ullong()); + inStream = (inStream >> 8); + } + + return res; +} + +int BeamHash_III::InitialiseState(blake2b_state& base_state) +{ + unsigned char personalization[BLAKE2B_PERSONALBYTES] = {}; + memcpy(personalization, "Beam-PoW", 8); + memcpy(personalization + 8, &workBitSize, 4); + memcpy(personalization + 12, &numRounds, 4); + + const uint8_t outlen = 32; + + blake2b_param param = {0}; + param.digest_length = outlen; + param.fanout = 1; + param.depth = 1; + + memcpy(¶m.personal, personalization, BLAKE2B_PERSONALBYTES); + return blake2b_init_param(&base_state, ¶m); +} + + +bool BeamHash_III::IsValidSolution(const blake2b_state& base_state, std::vector soln) +{ + if (soln.size() != 104) + { + return false; + } + + uint64_t prePow[4]; + blake2b_state state = base_state; + // Last 4 bytes of solution are our extra nonce + blake2b_update(&state, (uint8_t*)&soln[100], 4); + blake2b_final(&state, (uint8_t*)&prePow[0], static_cast(32)); + + // This will only evaluate bytes 0..99 + std::vector indices = GetIndicesFromMinimal(soln); + + std::vector X; + for (uint32_t i = 0; i < indices.size(); i++) + { + X.emplace_back(&prePow[0], indices[i]); + } + + uint32_t round = 1; + while (X.size() > 1) + { + std::vector Xtmp; + + for (size_t i = 0; i < X.size(); i += 2) + { + uint32_t remLen = workBitSize - (round - 1) * collisionBitSize; + if (round == 5) + remLen -= 64; + + X[i].applyMix(remLen); + X[i + 1].applyMix(remLen); + + if (!hasCollision(X[i], X[i + 1])) + { + // std::cout << "Collision Error" << i << " " << X.size() << " " << X[i].getCollisionBits() << " " << X[i+1].getCollisionBits() << std::endl; + return false; + } + + if (!distinctIndices(X[i], X[i + 1])) + { + // std::cout << "Non-Distinct" << i << " " << X.size() << std::endl; + return false; + } + + if (!indexAfter(X[i], X[i + 1])) + { + // std::cout << "Index Order" << i << " " << X.size() << std::endl; + return false; + } + + remLen = workBitSize - round * collisionBitSize; + if (round == 4) + remLen -= 64; + if (round == 5) + remLen = collisionBitSize; + + Xtmp.emplace_back(X[i], X[i + 1], remLen); + } + + X = Xtmp; + round++; + } + + return X[0].isZero(); +} + + +SolverCancelledException beamSolverCancelled; + +bool BeamHash_III::OptimisedSolve(const blake2b_state& base_state, + const std::function&)> validBlock, + const std::function cancelled) +{ + uint64_t prePow[4]; + blake2b_state state = base_state; + + uint8_t extraNonce[4] = {0}; + + blake2b_update(&state, (uint8_t*)&extraNonce, 4); + blake2b_final(&state, (uint8_t*)&prePow[0], static_cast(32)); + + std::vector elements; + elements.reserve(1 << (collisionBitSize + 1)); + + // Seeding + for (uint32_t i = 0; i < (1 << (collisionBitSize + 1)); i++) + { + elements.emplace_back(&prePow[0], i); + if (cancelled(ListGeneration)) + throw beamSolverCancelled; + } + + // Round 1 to 5 + uint32_t round; + for (round = 1; round < 5; round++) + { + uint32_t remLen = workBitSize - (round - 1) * collisionBitSize; + + // Mixing of elements + for (uint32_t i = 0; i < elements.size(); i++) + { + elements[i].applyMix(remLen); + if (cancelled(MixElements)) + throw beamSolverCancelled; + } + + // Sorting + std::sort(elements.begin(), elements.end(), sortStepElement); + if (cancelled(ListSorting)) + throw beamSolverCancelled; + + // Set length of output bits + remLen = workBitSize - round * collisionBitSize; + if (round == 4) + remLen -= 64; + + // Creating matches + std::vector outElements; + outElements.reserve(1 << (collisionBitSize + 1)); + + for (uint32_t i = 0; i < elements.size() - 1; i++) + { + uint32_t j = i + 1; + while (j < elements.size()) + { + if (hasCollision(elements[i], elements[j])) + { + outElements.emplace_back(elements[i], elements[j], remLen); + } + else + { + break; + } + j++; + } + if (cancelled(ListColliding)) + throw beamSolverCancelled; + } + + elements = outElements; + } + + // Check the output of the last round for solutions + uint32_t remLen = workBitSize - (round - 1) * collisionBitSize - 64; + + // Mixing of elements + for (uint32_t i = 0; i < elements.size(); i++) + { + elements[i].applyMix(remLen); + if (cancelled(MixElements)) + throw beamSolverCancelled; + } + + // Sorting + std::sort(elements.begin(), elements.end(), sortStepElement); + if (cancelled(ListSorting)) + throw beamSolverCancelled; + + // Set length of output bits + remLen = collisionBitSize; + + // Creating matches + for (uint32_t i = 0; i < elements.size() - 1; i++) + { + uint32_t j = i + 1; + while (j < elements.size()) + { + if (hasCollision(elements[i], elements[j])) + { + stepElem temp(elements[i], elements[j], remLen); + + if (temp.isZero()) + { + std::vector sol = GetMinimalFromIndices(temp.indexTree); + + // Adding the extra nonce + for (uint32_t k = 0; k < 4; k++) + sol.push_back(extraNonce[k]); + + if (validBlock(sol)) + return true; + } + } + else + { + break; + } + j++; + } + if (cancelled(ListColliding)) + throw beamSolverCancelled; + } + + return false; +} diff --git a/src/Native/libbeamhash/beamHashIII_imp.o b/src/Native/libbeamhash/beamHashIII_imp.o new file mode 100644 index 0000000000..b0e4f2faef Binary files /dev/null and b/src/Native/libbeamhash/beamHashIII_imp.o differ diff --git a/src/Native/libbeamhash/beamhashverify.cpp b/src/Native/libbeamhash/beamhashverify.cpp index 6ac56a7f75..5b0e6a1984 100644 --- a/src/Native/libbeamhash/beamhashverify.cpp +++ b/src/Native/libbeamhash/beamhashverify.cpp @@ -1,44 +1,45 @@ #include "beamhashverify.h" -#include -#include "crypto/beamHashIII.h" -#include "crypto/equihashR.h" -#include "beam/core/difficulty.h" -#include "beam/core/uintBig.h" -#include +bool verifyBH(const char* hdr, const char* nonceBuffer, const std::vector& soln, int pow) +{ + BeamHash_III BeamHashIII; -#include + eh_HashState state; -bool verifyBH(const char *hdr, const char *nonceBuffer, const std::vector &soln, int pow){ + switch (pow) + { + case 0: + BeamHashI.InitialiseState(state); + break; + case 1: + BeamHashII.InitialiseState(state); + break; + case 2: + BeamHashIII.InitialiseState(state); + break; + default: + throw std::invalid_argument("Unsupported PoW Parameter"); + } - eh_HashState state; - - switch (pow) { - case 0: BeamHashI.InitialiseState(state); - break; - case 1: BeamHashII.InitialiseState(state); - break; - case 2: BeamHashIII.InitialiseState(state); - break; - default: - throw std::invalid_argument("Unsupported PoW Parameter"); - } - - blake2b_update(&state, (const unsigned char *)hdr, 32); - blake2b_update(&state, (const unsigned char *)nonceBuffer, 8); - - bool isValid; - switch (pow) { - case 0: isValid = BeamHashI.IsValidSolution(state, soln); - break; - case 1: isValid = BeamHashII.IsValidSolution(state, soln); - break; - case 2: isValid = BeamHashIII.IsValidSolution(state, soln); - break; - default: - throw std::invalid_argument("Unsupported PoW Parameter"); - } + blake2b_update(&state, (const unsigned char*)hdr, 32); + blake2b_update(&state, (const unsigned char*)nonceBuffer, 8); - return isValid; -} \ No newline at end of file + bool isValid; + switch (pow) + { + case 0: + isValid = BeamHashI.IsValidSolution(state, soln); + break; + case 1: + isValid = BeamHashII.IsValidSolution(state, soln); + break; + case 2: + isValid = BeamHashIII.IsValidSolution(state, soln); + break; + default: + throw std::invalid_argument("Unsupported PoW Parameter"); + } + + return isValid; +} diff --git a/src/Native/libbeamhash/beamhashverify.h b/src/Native/libbeamhash/beamhashverify.h index 1632d80645..b9ef028aa3 100644 --- a/src/Native/libbeamhash/beamhashverify.h +++ b/src/Native/libbeamhash/beamhashverify.h @@ -1,24 +1,22 @@ #ifndef BEAMHASHVERIFY_H #define BEAMHASHVERIFY_H -#include -#include "crypto/beamHashIII.h" -#include "crypto/equihashR.h" -#include "beam/core/difficulty.h" -#include "beam/core/uintBig.h" - -#include - +#include "beamHashIII.h" +#include "equihashR.h" +#include #include #ifdef __cplusplus extern "C" { #endif -bool verifyBH(const char*, const char*, const std::vector&, int pow); +bool verifyBH(const char*, + const char*, + const std::vector&, + int pow); #ifdef __cplusplus } #endif -#endif \ No newline at end of file +#endif diff --git a/src/Native/libbeamhash/beamhashverify.o b/src/Native/libbeamhash/beamhashverify.o new file mode 100644 index 0000000000..af5b1cf351 Binary files /dev/null and b/src/Native/libbeamhash/beamhashverify.o differ diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2-config.h b/src/Native/libbeamhash/blake/blake2-config.h similarity index 74% rename from src/Native/libbeamhash/crypto/blake/sse/blake2-config.h rename to src/Native/libbeamhash/blake/blake2-config.h index ef6fd6b4c2..9ac2f980ca 100644 --- a/src/Native/libbeamhash/crypto/blake/sse/blake2-config.h +++ b/src/Native/libbeamhash/blake/blake2-config.h @@ -27,56 +27,56 @@ // These don't work everywhere #if defined(__SSE2__) -#define HAVE_SSE2 + #define HAVE_SSE2 #endif #if defined(__SSSE3__) -#define HAVE_SSSE3 + #define HAVE_SSSE3 #endif #if defined(__SSE4_1__) -#define HAVE_SSE41 + #define HAVE_SSE41 #endif #if defined(__AVX__) || defined(__AVX2__) -#define HAVE_AVX + #define HAVE_AVX #endif #if defined(__XOP__) -#define HAVE_XOP + #define HAVE_XOP #endif #ifdef HAVE_AVX2 -#ifndef HAVE_AVX -#define HAVE_AVX -#endif + #ifndef HAVE_AVX + #define HAVE_AVX + #endif #endif #ifdef HAVE_XOP -#ifndef HAVE_AVX -#define HAVE_AVX -#endif + #ifndef HAVE_AVX + #define HAVE_AVX + #endif #endif #ifdef HAVE_AVX -#ifndef HAVE_SSE41 -#define HAVE_SSE41 -#endif + #ifndef HAVE_SSE41 + #define HAVE_SSE41 + #endif #endif #ifdef HAVE_SSE41 -#ifndef HAVE_SSSE3 -#define HAVE_SSSE3 -#endif + #ifndef HAVE_SSSE3 + #define HAVE_SSSE3 + #endif #endif #ifdef HAVE_SSSE3 -#define HAVE_SSE2 + #define HAVE_SSE2 #endif #if !defined(HAVE_SSE2) -#error "This code requires at least SSE2." + #error "This code requires at least SSE2." #endif #endif diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2-impl.h b/src/Native/libbeamhash/blake/blake2-impl.h similarity index 100% rename from src/Native/libbeamhash/crypto/blake/sse/blake2-impl.h rename to src/Native/libbeamhash/blake/blake2-impl.h diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2-round.h b/src/Native/libbeamhash/blake/blake2-round.h similarity index 100% rename from src/Native/libbeamhash/crypto/blake/sse/blake2-round.h rename to src/Native/libbeamhash/blake/blake2-round.h diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2.h b/src/Native/libbeamhash/blake/blake2.h similarity index 100% rename from src/Native/libbeamhash/crypto/blake/sse/blake2.h rename to src/Native/libbeamhash/blake/blake2.h diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2b-load-sse2.h b/src/Native/libbeamhash/blake/blake2b-load-sse2.h similarity index 100% rename from src/Native/libbeamhash/crypto/blake/sse/blake2b-load-sse2.h rename to src/Native/libbeamhash/blake/blake2b-load-sse2.h diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2b-load-sse41.h b/src/Native/libbeamhash/blake/blake2b-load-sse41.h similarity index 100% rename from src/Native/libbeamhash/crypto/blake/sse/blake2b-load-sse41.h rename to src/Native/libbeamhash/blake/blake2b-load-sse41.h diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2b-round.h b/src/Native/libbeamhash/blake/blake2b-round.h similarity index 100% rename from src/Native/libbeamhash/crypto/blake/sse/blake2b-round.h rename to src/Native/libbeamhash/blake/blake2b-round.h diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2b.cpp b/src/Native/libbeamhash/blake/blake2b.cpp similarity index 100% rename from src/Native/libbeamhash/crypto/blake/sse/blake2b.cpp rename to src/Native/libbeamhash/blake/blake2b.cpp diff --git a/src/Native/libbeamhash/blake/blake2b.o b/src/Native/libbeamhash/blake/blake2b.o new file mode 100644 index 0000000000..eb5ee8c7bb Binary files /dev/null and b/src/Native/libbeamhash/blake/blake2b.o differ diff --git a/src/Native/libbeamhash/crypto/common.h b/src/Native/libbeamhash/common.h similarity index 97% rename from src/Native/libbeamhash/crypto/common.h rename to src/Native/libbeamhash/common.h index 60bdfa538f..01dde3b164 100644 --- a/src/Native/libbeamhash/crypto/common.h +++ b/src/Native/libbeamhash/common.h @@ -9,8 +9,8 @@ #include "bitcoin-config.h" #endif -#include #include +#include #if defined(_MSC_VER) || defined(__APPLE__) || defined(__ANDROID__) #include "compat/endian.h" @@ -66,4 +66,4 @@ void static inline WriteBE64(unsigned char* ptr, uint64_t x) *((uint64_t*)ptr) = htobe64(x); } -#endif // BITCOIN_CRYPTO_COMMON_H +#endif // BITCOIN_CRYPTO_COMMON_H \ No newline at end of file diff --git a/src/Native/libbeamhash/compat/byteswap.h b/src/Native/libbeamhash/compat/byteswap.h new file mode 100644 index 0000000000..01a0e7b547 --- /dev/null +++ b/src/Native/libbeamhash/compat/byteswap.h @@ -0,0 +1,40 @@ +// Copyright (c) 2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_COMPAT_BYTESWAP_H +#define BITCOIN_COMPAT_BYTESWAP_H + +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + +#include + +#if defined(HAVE_BYTESWAP_H) +#include +#endif + +#if HAVE_DECL_BSWAP_16 == 0 +inline uint16_t bswap_16(uint16_t x) +{ + return (x >> 8) | ((x & 0x00ff) << 8); +} +#endif // HAVE_DECL_BSWAP16 + +#if HAVE_DECL_BSWAP_32 == 0 +inline uint32_t bswap_32(uint32_t x) +{ + return (((x & 0xff000000U) >> 24) | ((x & 0x00ff0000U) >> 8) | + ((x & 0x0000ff00U) << 8) | ((x & 0x000000ffU) << 24)); +} +#endif // HAVE_DECL_BSWAP32 + +#if HAVE_DECL_BSWAP_64 == 0 +inline uint64_t bswap_64(uint64_t x) +{ + return (((x & 0xff00000000000000ull) >> 56) | ((x & 0x00ff000000000000ull) >> 40) | ((x & 0x0000ff0000000000ull) >> 24) | ((x & 0x000000ff00000000ull) >> 8) | ((x & 0x00000000ff000000ull) << 8) | ((x & 0x0000000000ff0000ull) << 24) | ((x & 0x000000000000ff00ull) << 40) | ((x & 0x00000000000000ffull) << 56)); +} +#endif // HAVE_DECL_BSWAP64 + +#endif // BITCOIN_COMPAT_BYTESWAP_H \ No newline at end of file diff --git a/src/Native/libbeamhash/crypto/compat/endian.h b/src/Native/libbeamhash/compat/endian.h similarity index 80% rename from src/Native/libbeamhash/crypto/compat/endian.h rename to src/Native/libbeamhash/compat/endian.h index 167bce5b92..90b8cc50f0 100644 --- a/src/Native/libbeamhash/crypto/compat/endian.h +++ b/src/Native/libbeamhash/compat/endian.h @@ -26,171 +26,171 @@ inline uint16_t htobe16(uint16_t host_16bits) { return host_16bits; } -#endif // HAVE_DECL_HTOBE16 +#endif // HAVE_DECL_HTOBE16 #if HAVE_DECL_HTOLE16 == 0 inline uint16_t htole16(uint16_t host_16bits) { return bswap_16(host_16bits); } -#endif // HAVE_DECL_HTOLE16 +#endif // HAVE_DECL_HTOLE16 #if HAVE_DECL_BE16TOH == 0 inline uint16_t be16toh(uint16_t big_endian_16bits) { return big_endian_16bits; } -#endif // HAVE_DECL_BE16TOH +#endif // HAVE_DECL_BE16TOH #if HAVE_DECL_LE16TOH == 0 inline uint16_t le16toh(uint16_t little_endian_16bits) { return bswap_16(little_endian_16bits); } -#endif // HAVE_DECL_LE16TOH +#endif // HAVE_DECL_LE16TOH #if HAVE_DECL_HTOBE32 == 0 inline uint32_t htobe32(uint32_t host_32bits) { return host_32bits; } -#endif // HAVE_DECL_HTOBE32 +#endif // HAVE_DECL_HTOBE32 #if HAVE_DECL_HTOLE32 == 0 inline uint32_t htole32(uint32_t host_32bits) { return bswap_32(host_32bits); } -#endif // HAVE_DECL_HTOLE32 +#endif // HAVE_DECL_HTOLE32 #if HAVE_DECL_BE32TOH == 0 inline uint32_t be32toh(uint32_t big_endian_32bits) { return big_endian_32bits; } -#endif // HAVE_DECL_BE32TOH +#endif // HAVE_DECL_BE32TOH #if HAVE_DECL_LE32TOH == 0 inline uint32_t le32toh(uint32_t little_endian_32bits) { return bswap_32(little_endian_32bits); } -#endif // HAVE_DECL_LE32TOH +#endif // HAVE_DECL_LE32TOH #if HAVE_DECL_HTOBE64 == 0 inline uint64_t htobe64(uint64_t host_64bits) { return host_64bits; } -#endif // HAVE_DECL_HTOBE64 +#endif // HAVE_DECL_HTOBE64 #if HAVE_DECL_HTOLE64 == 0 inline uint64_t htole64(uint64_t host_64bits) { return bswap_64(host_64bits); } -#endif // HAVE_DECL_HTOLE64 +#endif // HAVE_DECL_HTOLE64 #if HAVE_DECL_BE64TOH == 0 inline uint64_t be64toh(uint64_t big_endian_64bits) { return big_endian_64bits; } -#endif // HAVE_DECL_BE64TOH +#endif // HAVE_DECL_BE64TOH #if HAVE_DECL_LE64TOH == 0 inline uint64_t le64toh(uint64_t little_endian_64bits) { return bswap_64(little_endian_64bits); } -#endif // HAVE_DECL_LE64TOH +#endif // HAVE_DECL_LE64TOH -#else // WORDS_BIGENDIAN +#else // WORDS_BIGENDIAN #if HAVE_DECL_HTOBE16 == 0 inline uint16_t htobe16(uint16_t host_16bits) { return bswap_16(host_16bits); } -#endif // HAVE_DECL_HTOBE16 +#endif // HAVE_DECL_HTOBE16 #if HAVE_DECL_HTOLE16 == 0 inline uint16_t htole16(uint16_t host_16bits) { return host_16bits; } -#endif // HAVE_DECL_HTOLE16 +#endif // HAVE_DECL_HTOLE16 #if HAVE_DECL_BE16TOH == 0 inline uint16_t be16toh(uint16_t big_endian_16bits) { return bswap_16(big_endian_16bits); } -#endif // HAVE_DECL_BE16TOH +#endif // HAVE_DECL_BE16TOH #if HAVE_DECL_LE16TOH == 0 inline uint16_t le16toh(uint16_t little_endian_16bits) { return little_endian_16bits; } -#endif // HAVE_DECL_LE16TOH +#endif // HAVE_DECL_LE16TOH #if HAVE_DECL_HTOBE32 == 0 inline uint32_t htobe32(uint32_t host_32bits) { return bswap_32(host_32bits); } -#endif // HAVE_DECL_HTOBE32 +#endif // HAVE_DECL_HTOBE32 #if HAVE_DECL_HTOLE32 == 0 inline uint32_t htole32(uint32_t host_32bits) { return host_32bits; } -#endif // HAVE_DECL_HTOLE32 +#endif // HAVE_DECL_HTOLE32 #if HAVE_DECL_BE32TOH == 0 inline uint32_t be32toh(uint32_t big_endian_32bits) { return bswap_32(big_endian_32bits); } -#endif // HAVE_DECL_BE32TOH +#endif // HAVE_DECL_BE32TOH #if HAVE_DECL_LE32TOH == 0 inline uint32_t le32toh(uint32_t little_endian_32bits) { return little_endian_32bits; } -#endif // HAVE_DECL_LE32TOH +#endif // HAVE_DECL_LE32TOH #if HAVE_DECL_HTOBE64 == 0 inline uint64_t htobe64(uint64_t host_64bits) { return bswap_64(host_64bits); } -#endif // HAVE_DECL_HTOBE64 +#endif // HAVE_DECL_HTOBE64 #if HAVE_DECL_HTOLE64 == 0 inline uint64_t htole64(uint64_t host_64bits) { return host_64bits; } -#endif // HAVE_DECL_HTOLE64 +#endif // HAVE_DECL_HTOLE64 #if HAVE_DECL_BE64TOH == 0 inline uint64_t be64toh(uint64_t big_endian_64bits) { return bswap_64(big_endian_64bits); } -#endif // HAVE_DECL_BE64TOH +#endif // HAVE_DECL_BE64TOH #if HAVE_DECL_LE64TOH == 0 inline uint64_t le64toh(uint64_t little_endian_64bits) { return little_endian_64bits; } -#endif // HAVE_DECL_LE64TOH +#endif // HAVE_DECL_LE64TOH -#endif // WORDS_BIGENDIAN +#endif // WORDS_BIGENDIAN -#endif // BITCOIN_COMPAT_ENDIAN_H \ No newline at end of file +#endif // BITCOIN_COMPAT_ENDIAN_H \ No newline at end of file diff --git a/src/Native/libbeamhash/crypto/beamHashIII.cpp b/src/Native/libbeamhash/crypto/beamHashIII.cpp deleted file mode 100644 index bf1d4c5231..0000000000 --- a/src/Native/libbeamhash/crypto/beamHashIII.cpp +++ /dev/null @@ -1,379 +0,0 @@ - -#include "beamHashIII.h" - - -namespace sipHash { - -static uint64_t rotl(uint64_t x, uint64_t b) { - return (x << b) | (x >> (64 - b)); -} - -#define sipRound() { \ - v0 += v1; v2 += v3; \ - v1 = rotl(v1,13); \ - v3 = rotl(v3,16); \ - v1 ^= v0; v3 ^= v2; \ - v0 = rotl(v0,32); \ - v2 += v1; v0 += v3; \ - v1 = rotl(v1,17); \ - v3 = rotl(v3,21); \ - v1 ^= v2; v3 ^= v0; \ - v2 = rotl(v2,32); \ -} - -uint64_t siphash24(uint64_t state0, uint64_t state1, uint64_t state2, uint64_t state3, uint64_t nonce) { - uint64_t v0, v1, v2, v3; - - v0 = state0; v1=state1; v2=state2; v3=state3; - v3 ^= nonce; - sipRound(); - sipRound(); - v0 ^= nonce; - v2 ^= 0xff; - sipRound(); - sipRound(); - sipRound(); - sipRound(); - - return (v0 ^ v1 ^ v2 ^ v3); -} - -} //end namespace sipHash - - -stepElem::stepElem(const uint64_t * prePow, uint32_t index) { - workBits.reset(); - - for (int32_t i=6; i>=0; i--) { - workBits = (workBits << 64); - uint64_t hash=sipHash::siphash24(prePow[0],prePow[1],prePow[2],prePow[3],(index << 3)+i); - workBits |= hash; - } - - indexTree.assign(1, index); -} - -stepElem::stepElem(const stepElem &a, const stepElem &b, uint32_t remLen) { - // Create a new rounds step element from matching two ancestors - workBits.reset(); - - workBits = a.workBits ^ b.workBits; - workBits = (workBits >> collisionBitSize); - - std::bitset mask; - mask.set(); - mask = (mask >> (workBitSize-remLen)); - workBits &= mask; - - if (a.indexTree[0] < b.indexTree[0]) { - indexTree.insert(indexTree.end(), a.indexTree.begin(), a.indexTree.end()); - indexTree.insert(indexTree.end(), b.indexTree.begin(), b.indexTree.end()); - } else { - indexTree.insert(indexTree.end(), b.indexTree.begin(), b.indexTree.end()); - indexTree.insert(indexTree.end(), a.indexTree.begin(), a.indexTree.end()); - } -} - -void stepElem::applyMix(uint32_t remLen) { - std::bitset<512> tempBits(workBits.to_string()); - - // Add in the bits of the index tree to the end of work bits - uint32_t padNum = ((512-remLen) + collisionBitSize) / (collisionBitSize + 1); - padNum = std::min(padNum, indexTree.size()); - - for (uint32_t i=0; i tmp(indexTree[i]); - tmp = tmp << (remLen+i*(collisionBitSize + 1)); - tempBits |= tmp; - } - - - // Applyin the mix from the lined up bits - std::bitset<512> mask(0xFFFFFFFFFFFFFFFFUL); - uint64_t result = 0; - for (uint32_t i=0; i<8; i++) { - uint64_t tmp = (tempBits & mask).to_ulong(); - tempBits = tempBits >> 64; - - result += sipHash::rotl(tmp, (29*(i+1)) & 0x3F); - } - result = sipHash::rotl(result, 24); - - - // Wipe out lowest 64 bits in favor of the mixed bits - workBits = (workBits >> 64); - workBits = (workBits << 64); - workBits |= std::bitset(result); -} - -uint32_t stepElem::getCollisionBits() const { - std::bitset mask((1 << collisionBitSize) - 1); - return (uint32_t) (workBits & mask).to_ulong(); -} - -bool stepElem::isZero() { - return workBits.none(); -} - -uint64_t getLowBits(stepElem test) { - std::bitset mask(~0); - return (uint64_t) (test.workBits & mask).to_ulong(); -} -/******** - - Friend Functions to compare step elements - -********/ - - -bool hasCollision(stepElem &a, stepElem &b) { - return (a.getCollisionBits() == b.getCollisionBits()); -} - -bool distinctIndices(stepElem &a, stepElem &b) { - for (uint32_t indexA : a.indexTree) { - for (uint32_t indexB : b.indexTree) { - if (indexA == indexB) return false; - } - } - return true; -} - -bool indexAfter(stepElem &a, stepElem &b) { - return (a.indexTree[0] < b.indexTree[0]); -} - -bool sortStepElement(const stepElem &a, const stepElem &b) { - return (a.getCollisionBits() < b.getCollisionBits()); -} - - -/******** - - Beam Hash III Verify Functions & CPU Miner - -********/ - -std::vector GetIndicesFromMinimal(std::vector soln) { - std::bitset<800> inStream; - std::bitset<800> mask((1 << (collisionBitSize+1))-1); - - inStream.reset(); - for (int32_t i = 99; i>=0; i--) { - inStream = (inStream << 8); - inStream |= (uint64_t) soln[i]; - } - - std::vector res; - for (uint32_t i=0; i<32; i++) { - res.push_back((uint32_t) (inStream & mask).to_ulong() ); - inStream = (inStream >> (collisionBitSize+1)); - } - - return res; -} - -std::vector GetMinimalFromIndices(std::vector sol) { - std::bitset<800> inStream; - std::bitset<800> mask(0xFF); - - inStream.reset(); - for (int32_t i = sol.size(); i>=0; i--) { - inStream = (inStream << (collisionBitSize+1)); - inStream |= (uint64_t) sol[i]; - } - - std::vector res; - for (uint32_t i=0; i<100; i++) { - res.push_back((uint8_t) (inStream & mask).to_ulong() ); - inStream = (inStream >> 8); - } - - return res; -} - -int BeamHash_III::InitialiseState(blake2b_state& base_state) { - unsigned char personalization[BLAKE2B_PERSONALBYTES] = {}; - memcpy(personalization, "Beam-PoW", 8); - memcpy(personalization+8, &workBitSize, 4); - memcpy(personalization+12, &numRounds, 4); - - const uint8_t outlen = 32; - - blake2b_param param = {0}; - param.digest_length = outlen; - param.fanout = 1; - param.depth = 1; - - memcpy(¶m.personal, personalization, BLAKE2B_PERSONALBYTES); - return blake2b_init_param(&base_state, ¶m); -} - - -bool BeamHash_III::IsValidSolution(const blake2b_state& base_state, std::vector soln) { - - if (soln.size() != 104) { - return false; - } - - uint64_t prePow[4]; - blake2b_state state = base_state; - // Last 4 bytes of solution are our extra nonce - blake2b_update(&state, (uint8_t*) &soln[100], 4); - blake2b_final(&state, (uint8_t*) &prePow[0], static_cast(32)); - - // This will only evaluate bytes 0..99 - std::vector indices = GetIndicesFromMinimal(soln); - - std::vector X; - for (uint32_t i=0; i 1) { - std::vector Xtmp; - - for (size_t i = 0; i < X.size(); i += 2) { - uint32_t remLen = workBitSize-(round-1)*collisionBitSize; - if (round == 5) remLen -= 64; - - X[i].applyMix(remLen); - X[i+1].applyMix(remLen); - - if (!hasCollision(X[i], X[i+1])) { - //std::cout << "Collision Error" << i << " " << X.size() << " " << X[i].getCollisionBits() << " " << X[i+1].getCollisionBits() << std::endl; - return false; - } - - if (!distinctIndices(X[i], X[i+1])) { - //std::cout << "Non-Distinct" << i << " " << X.size() << std::endl; - return false; - } - - if (!indexAfter(X[i], X[i+1])) { - //std::cout << "Index Order" << i << " " << X.size() << std::endl; - return false; - } - - remLen = workBitSize-round*collisionBitSize; - if (round == 4) remLen -= 64; - if (round == 5) remLen = collisionBitSize; - - Xtmp.emplace_back(X[i], X[i+1], remLen); - } - - X = Xtmp; - round++; - } - - return X[0].isZero(); -} - -#ifdef ENABLE_MINING -SolverCancelledException beamSolverCancelled; - -bool BeamHash_III::OptimisedSolve(const blake2b_state& base_state, - const std::function&)> validBlock, - const std::function cancelled) { - - uint64_t prePow[4]; - blake2b_state state = base_state; - - uint8_t extraNonce[4] = {0}; - - blake2b_update(&state, (uint8_t*) &extraNonce, 4); - blake2b_final(&state, (uint8_t*) &prePow[0], static_cast(32)); - - std::vector elements; - elements.reserve(1 << (collisionBitSize+1)); - - // Seeding - for (uint32_t i=0; i<(1 << (collisionBitSize+1)); i++) { - elements.emplace_back(&prePow[0], i); - if (cancelled(ListGeneration)) throw beamSolverCancelled; - } - - // Round 1 to 5 - uint32_t round; - for (round=1; round<5; round++) { - - uint32_t remLen = workBitSize-(round-1)*collisionBitSize; - - // Mixing of elements - for (uint32_t i=0; i outElements; - outElements.reserve(1 << (collisionBitSize+1)); - - for (uint32_t i=0; i sol = GetMinimalFromIndices(temp.indexTree); - - // Adding the extra nonce - for (uint32_t i=0; i<4; i++) sol.push_back(extraNonce[i]); - - if (validBlock(sol)) return true; - } - } else { - break; - } - j++; - } - if (cancelled(ListColliding)) throw beamSolverCancelled; - } - - return false; -} -#endif - diff --git a/src/Native/libbeamhash/crypto/beamHashIII.h b/src/Native/libbeamhash/crypto/beamHashIII.h deleted file mode 100644 index 2ecab2d625..0000000000 --- a/src/Native/libbeamhash/crypto/beamHashIII.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2020 The Beam Team - -#ifndef BEAMHASH_H -#define BEAMHASH_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "powScheme.h" - -const uint32_t workBitSize=448; -const uint32_t collisionBitSize=24; -const uint32_t numRounds=5; - -class stepElem { - friend class BeamHash_III; - - private: - std::bitset workBits; - std::vector indexTree; - - public: - stepElem(const uint64_t * prePow, uint32_t index); - stepElem(const stepElem &a, const stepElem &b, uint32_t remLen); - - void applyMix(uint32_t remLen); - uint32_t getCollisionBits() const; - bool isZero(); - - friend bool hasCollision(stepElem &a, stepElem &b); - friend bool distinctIndices(stepElem &a, stepElem &b); - friend bool indexAfter(stepElem &a, stepElem &b); - friend uint64_t getLowBits(stepElem test); -}; - -class BeamHash_III : public PoWScheme { - public: - int InitialiseState(blake2b_state& base_state); - bool IsValidSolution(const blake2b_state& base_state, std::vector soln); - - #ifdef ENABLE_MINING - bool OptimisedSolve(const blake2b_state& base_state, - const std::function&)> validBlock, - const std::function cancelled); - #endif -}; - -static BeamHash_III BeamHashIII; - - - -#endif diff --git a/src/Native/libbeamhash/crypto/blake/ref/Makefile b/src/Native/libbeamhash/crypto/blake/ref/Makefile deleted file mode 100644 index 73e556892f..0000000000 --- a/src/Native/libbeamhash/crypto/blake/ref/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -CC=gcc -CFLAGS=-O2 -I../testvectors -Wall -Wextra -std=c89 -pedantic -Wno-long-long -BLAKEBINS=blake2b - -all: $(BLAKEBINS) check - -blake2b: blake2b-ref.c - $(CC) blake2b-ref.c -o $@ $(CFLAGS) -DBLAKE2B_SELFTEST - -check: blake2b - ./blake2b - -clean: - rm -rf *.o $(BLAKEBINS) diff --git a/src/Native/libbeamhash/crypto/equihashR.cpp b/src/Native/libbeamhash/crypto/equihashR.cpp deleted file mode 100644 index 43f9d2e846..0000000000 --- a/src/Native/libbeamhash/crypto/equihashR.cpp +++ /dev/null @@ -1,708 +0,0 @@ -// Copyright (c) 2019 The Beam Team - -// Based on Reference Implementation of the Equihash Proof-of-Work algorithm. -// Copyright (c) 2016 Jack Grigg -// Copyright (c) 2016 The Zcash developers - -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -// Resources: -// Alex Biryukov and Dmitry Khovratovich -// Equihash: Asymmetric Proof-of-Work Based on the Generalized Birthday Problem -// NDSS ’16, 21-24 February 2016, San Diego, CA, USA -// https://www.internetsociety.org/sites/default/files/blogs-media/equihash-asymmetric-proof-of-work-based-generalized-birthday-problem.pdf - -//#include "compat/endian.h" -#include "equihashR.h" -//#include "util.h" - -#include -#include -#include -#include - -SolverCancelledException solver_cancelled; - -namespace -{ - void ZeroizeUnusedBits(size_t N, size_t R, unsigned char* hash, size_t hLen) - { - uint8_t rem = N % 8; - const size_t step = GetSizeInBytes(N); - - if (rem) - { - // clear lowest 8-rem bits - for (size_t i = step - 1; i < hLen; i += step) { - uint8_t b = 0xff << (8-rem); - hash[i] &= b; - } - } - - if (R) { - for (size_t i = 0; i < hLen; i += step) { - uint8_t b = 0xff >> (2*R); - hash[i] &= b; - } - } - } -} - -template -int EquihashR::InitialiseState(eh_HashState& base_state) -{ - uint32_t le_N = htole32(N); - uint32_t le_K = htole32(K); - - unsigned char personalization[BLAKE2B_PERSONALBYTES] = {}; - memcpy(personalization, "Beam-PoW", 8); - memcpy(personalization+8, &le_N, 4); - memcpy(personalization+12, &le_K, 4); - - const uint8_t outlen = (512 / N) * GetSizeInBytes(N); - - static_assert(!((!outlen) || (outlen > BLAKE2B_OUTBYTES))); - - blake2b_param param = {0}; - param.digest_length = outlen; - param.fanout = 1; - param.depth = 1; - - memcpy(¶m.personal, personalization, BLAKE2B_PERSONALBYTES); - - return blake2b_init_param(&base_state, ¶m); -} - -void GenerateHash(const eh_HashState& base_state, eh_index g, - unsigned char* hash, size_t hLen, size_t N, size_t R ) -{ - - - uint32_t myHash[16] = {0}; - uint32_t startIndex = g & 0xFFFFFFF0; - - for (uint32_t g2 = startIndex; g2 <= g; g2++) { - uint32_t tmpHash[16] = {0}; - - eh_HashState state; - state = base_state; - eh_index lei = htole32(g2); - blake2b_update(&state, (const unsigned char*) &lei, - sizeof(eh_index)); - - blake2b_final(&state, (unsigned char*)&tmpHash[0], static_cast(hLen)); - - for (uint32_t idx = 0; idx < 16; idx++) myHash[idx] += tmpHash[idx]; - } - - memcpy(hash, &myHash[0], hLen); - ZeroizeUnusedBits(N, R, hash, hLen); -} - -void ExpandArray(const unsigned char* in, size_t in_len, - unsigned char* out, size_t out_len, - size_t bit_len, size_t byte_pad) -{ - assert(bit_len >= 8); - assert(8*sizeof(uint32_t) >= bit_len); - - size_t out_width { (bit_len+7)/8 + byte_pad }; - assert(out_len == 8*out_width*in_len/bit_len); - - uint32_t bit_len_mask { ((uint32_t)1 << bit_len) - 1 }; - - // The acc_bits least-significant bits of acc_value represent a bit sequence - // in big-endian order. - size_t acc_bits = 0; - uint32_t acc_value = 0; - - size_t j = 0; - for (size_t i = 0; i < in_len; i++) { - acc_value = (acc_value << 8) | in[i]; - acc_bits += 8; - - // When we have bit_len or more bits in the accumulator, write the next - // output element. - if (acc_bits >= bit_len) { - acc_bits -= bit_len; - for (size_t x = 0; x < byte_pad; x++) { - out[j+x] = 0; - } - for (size_t x = byte_pad; x < out_width; x++) { - out[j+x] = ( - // Big-endian - acc_value >> (acc_bits+(8*(out_width-x-1))) - ) & ( - // Apply bit_len_mask across byte boundaries - (bit_len_mask >> (8*(out_width-x-1))) & 0xFF - ); - } - j += out_width; - } - } -} - -void CompressArray(const unsigned char* in, size_t in_len, - unsigned char* out, size_t out_len, - size_t bit_len, size_t byte_pad) -{ - assert(bit_len >= 8); - assert(8*sizeof(uint32_t) >= bit_len); - - size_t in_width { (bit_len+7)/8 + byte_pad }; - assert(out_len == (bit_len*in_len/in_width + 7)/8); - - uint32_t bit_len_mask { ((uint32_t)1 << bit_len) - 1 }; - - // The acc_bits least-significant bits of acc_value represent a bit sequence - // in big-endian order. - size_t acc_bits = 0; - uint32_t acc_value = 0; - - size_t j = 0; - for (size_t i = 0; i < out_len; i++) { - // When we have fewer than 8 bits left in the accumulator, read the next - // input element. - if (acc_bits < 8) { - if (j < in_len) { - acc_value = acc_value << bit_len; - for (size_t x = byte_pad; x < in_width; x++) { - acc_value = acc_value | ( - ( - // Apply bit_len_mask across byte boundaries - in[j + x] & ((bit_len_mask >> (8 * (in_width - x - 1))) & 0xFF) - ) << (8 * (in_width - x - 1))); // Big-endian - } - j += in_width; - acc_bits += bit_len; - } - else { - acc_value <<= 8 - acc_bits; - acc_bits += 8 - acc_bits;; - } - } - - acc_bits -= 8; - out[i] = (acc_value >> acc_bits) & 0xFF; - } -} - -// Big-endian so that lexicographic array comparison is equivalent to integer -// comparison -void EhIndexToArray(const eh_index i, unsigned char* array) -{ - static_assert(sizeof(eh_index) == 4); - eh_index bei = htobe32(i); - memcpy(array, &bei, sizeof(eh_index)); -} - -// Big-endian so that lexicographic array comparison is equivalent to integer -// comparison -eh_index ArrayToEhIndex(const unsigned char* array) -{ - static_assert(sizeof(eh_index) == 4); - eh_index bei; - memcpy(&bei, array, sizeof(eh_index)); - return be32toh(bei); -} - -eh_trunc TruncateIndex(const eh_index i, const unsigned int ilen) -{ - // Truncate to 8 bits - static_assert(sizeof(eh_trunc) == 1); - return (i >> (ilen - 8)) & 0xff; -} - -eh_index UntruncateIndex(const eh_trunc t, const eh_index r, const unsigned int ilen) -{ - eh_index i{t}; - return (i << (ilen - 8)) | r; -} - -std::vector GetIndicesFromMinimal(std::vector minimal, - size_t cBitLen) -{ - assert(((cBitLen+1)+7)/8 <= sizeof(eh_index)); - size_t lenIndices { 8*sizeof(eh_index)*minimal.size()/(cBitLen+1) }; - size_t bytePad { sizeof(eh_index) - ((cBitLen+1)+7)/8 }; - std::vector array(lenIndices); - ExpandArray(minimal.data(), minimal.size(), - array.data(), lenIndices, cBitLen+1, bytePad); - std::vector ret; - for (size_t i = 0; i < lenIndices; i += sizeof(eh_index)) { - ret.push_back(ArrayToEhIndex(array.data()+i)); - } - return ret; -} - -std::vector GetMinimalFromIndices(std::vector indices, - size_t cBitLen) -{ - assert(((cBitLen+1)+7)/8 <= sizeof(eh_index)); - size_t lenIndices { indices.size()*sizeof(eh_index) }; - size_t minLen { (cBitLen+1)*lenIndices/(8*sizeof(eh_index)) }; - size_t bytePad { sizeof(eh_index) - ((cBitLen+1)+7)/8 }; - std::vector array(lenIndices); - for (size_t i = 0; i < indices.size(); i++) { - EhIndexToArray(indices[i], array.data()+(i*sizeof(eh_index))); - } - std::vector ret(minLen); - CompressArray(array.data(), lenIndices, - ret.data(), minLen, cBitLen+1, bytePad); - return ret; -} - -template -StepRow::StepRow(const unsigned char* hashIn, size_t hInLen, - size_t hLen, size_t cBitLen) -{ - assert(hLen <= WIDTH); - ExpandArray(hashIn, hInLen, hash, hLen, cBitLen); -} - -template template -StepRow::StepRow(const StepRow& a) -{ - static_assert(W <= WIDTH); - std::copy(a.hash, a.hash+W, hash); -} - -template -FullStepRow::FullStepRow(const unsigned char* hashIn, size_t hInLen, - size_t hLen, size_t cBitLen, eh_index i) : - StepRow {hashIn, hInLen, hLen, cBitLen} -{ - EhIndexToArray(i, hash+hLen); -} - -template template -FullStepRow::FullStepRow(const FullStepRow& a, const FullStepRow& b, size_t len, size_t lenIndices, size_t trim) : - StepRow {a} -{ - assert(len+lenIndices <= W); - assert(len-trim+(2*lenIndices) <= WIDTH); - for (size_t i = trim; i < len; i++) - hash[i-trim] = a.hash[i] ^ b.hash[i]; - if (a.IndicesBefore(b, len, lenIndices)) { - std::copy(a.hash+len, a.hash+len+lenIndices, hash+len-trim); - std::copy(b.hash+len, b.hash+len+lenIndices, hash+len-trim+lenIndices); - } else { - std::copy(b.hash+len, b.hash+len+lenIndices, hash+len-trim); - std::copy(a.hash+len, a.hash+len+lenIndices, hash+len-trim+lenIndices); - } -} - -template -FullStepRow& FullStepRow::operator=(const FullStepRow& a) -{ - std::copy(a.hash, a.hash+WIDTH, hash); - return *this; -} - -template -bool StepRow::IsZero(size_t len) -{ - // This doesn't need to be constant time. - for (size_t i = 0; i < len; i++) { - if (hash[i] != 0) - return false; - } - return true; -} - -template -std::vector FullStepRow::GetIndices(size_t len, size_t lenIndices, - size_t cBitLen) const -{ - assert(((cBitLen+1)+7)/8 <= sizeof(eh_index)); - size_t minLen { (cBitLen+1)*lenIndices/(8*sizeof(eh_index)) }; - size_t bytePad { sizeof(eh_index) - ((cBitLen+1)+7)/8 }; - std::vector ret(minLen); - CompressArray(hash+len, lenIndices, ret.data(), minLen, cBitLen+1, bytePad); - return ret; -} - -template -bool HasCollision(StepRow& a, StepRow& b, size_t l) -{ - // This doesn't need to be constant time. - for (size_t j = 0; j < l; j++) { - if (a.hash[j] != b.hash[j]) - return false; - } - return true; -} - -template -TruncatedStepRow::TruncatedStepRow(const unsigned char* hashIn, size_t hInLen, - size_t hLen, size_t cBitLen, - eh_index i, unsigned int ilen) : - StepRow {hashIn, hInLen, hLen, cBitLen} -{ - hash[hLen] = TruncateIndex(i, ilen); -} - -template template -TruncatedStepRow::TruncatedStepRow(const TruncatedStepRow& a, const TruncatedStepRow& b, size_t len, size_t lenIndices, int trim) : - StepRow {a} -{ - assert(len+lenIndices <= W); - assert(len-trim+(2*lenIndices) <= WIDTH); - for (size_t i = static_cast(trim); i < len; i++) - hash[i-trim] = a.hash[i] ^ b.hash[i]; - if (a.IndicesBefore(b, len, lenIndices)) { - std::copy(a.hash+len, a.hash+len+lenIndices, hash+len-trim); - std::copy(b.hash+len, b.hash+len+lenIndices, hash+len-trim+lenIndices); - } else { - std::copy(b.hash+len, b.hash+len+lenIndices, hash+len-trim); - std::copy(a.hash+len, a.hash+len+lenIndices, hash+len-trim+lenIndices); - } -} - -template -TruncatedStepRow& TruncatedStepRow::operator=(const TruncatedStepRow& a) -{ - std::copy(a.hash, a.hash+WIDTH, hash); - return *this; -} - -template -std::shared_ptr TruncatedStepRow::GetTruncatedIndices(size_t len, size_t lenIndices) const -{ - std::shared_ptr p (new eh_trunc[lenIndices], std::default_delete()); - std::copy(hash+len, hash+len+lenIndices, p.get()); - return p; -} - -#ifdef ENABLE_MINING - - -template -void CollideBranches(std::vector>& X, const size_t hlen, const size_t lenIndices, const unsigned int clen, const unsigned int ilen, const eh_trunc lt, const eh_trunc rt) -{ - size_t i = 0; - size_t posFree = 0; - assert(X.size() > 0); - std::vector> Xc; - while (i < X.size() - 1) { - // 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits - size_t j = 1; - while (i+j < X.size() && - HasCollision(X[i], X[i+j], clen)) { - j++; - } - - // 2c) Calculate tuples (X_i ^ X_j, (i, j)) - for (size_t l = 0; l < j - 1; l++) { - for (size_t m = l + 1; m < j; m++) { - if (DistinctIndices(X[i+l], X[i+m], hlen, lenIndices)) { - if (IsValidBranch(X[i+l], hlen, ilen, lt) && IsValidBranch(X[i+m], hlen, ilen, rt)) { - Xc.emplace_back(X[i+l], X[i+m], hlen, lenIndices, clen); - } else if (IsValidBranch(X[i+m], hlen, ilen, lt) && IsValidBranch(X[i+l], hlen, ilen, rt)) { - Xc.emplace_back(X[i+m], X[i+l], hlen, lenIndices, clen); - } - } - } - } - - // 2d) Store tuples on the table in-place if possible - while (posFree < i+j && Xc.size() > 0) { - X[posFree++] = Xc.back(); - Xc.pop_back(); - } - - i += j; - } - - // 2e) Handle edge case where final table entry has no collision - while (posFree < X.size() && Xc.size() > 0) { - X[posFree++] = Xc.back(); - Xc.pop_back(); - } - - if (Xc.size() > 0) { - // 2f) Add overflow to end of table - X.insert(X.end(), Xc.begin(), Xc.end()); - } else if (posFree < X.size()) { - // 2g) Remove empty space at the end - X.erase(X.begin()+posFree, X.end()); - X.shrink_to_fit(); - } -} - -template -bool EquihashR::OptimisedSolve(const eh_HashState& base_state, - const std::function&)> validBlock, - const std::function cancelled) -{ - eh_index init_size { 1U << (CollisionBitLength + 1 - R) }; - eh_index recreate_size { UntruncateIndex(1, 0, CollisionBitLength + 1) }; - - // First run the algorithm with truncated indices - - const eh_index soln_size { 1 << K }; - std::vector> partialSolns; - int invalidCount = 0; - { - - // 1) Generate first list - size_t hashLen = HashLength; - size_t lenIndices = sizeof(eh_trunc); - std::vector> Xt; - Xt.reserve(init_size); - unsigned char tmpHash[HashOutput]; - for (eh_index g = 0; Xt.size() < init_size; g++) { - GenerateHash(base_state, g, tmpHash, HashOutput, N, R); - for (eh_index i = 0; i < IndicesPerHashOutput && Xt.size() < init_size; i++) { - Xt.emplace_back(tmpHash+(i*GetSizeInBytes(N)), GetSizeInBytes(N), HashLength, CollisionBitLength, - static_cast(g*IndicesPerHashOutput)+i, static_cast(CollisionBitLength + 1)); - } - if (cancelled(ListGeneration)) throw solver_cancelled; - } - - // 3) Repeat step 2 until 2n/(k+1) bits remain - for (unsigned int r = 1; r < K && Xt.size() > 0; r++) { - // 2a) Sort the list - std::sort(Xt.begin(), Xt.end(), CompareSR(CollisionByteLength)); - if (cancelled(ListSorting)) throw solver_cancelled; - - size_t i = 0; - size_t posFree = 0; - std::vector> Xc; - while (i < Xt.size() - 1) { - // 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits - size_t j = 1; - while (i+j < Xt.size() && - HasCollision(Xt[i], Xt[i+j], CollisionByteLength)) { - j++; - } - - // 2c) Calculate tuples (X_i ^ X_j, (i, j)) - //bool checking_for_zero = (i == 0 && Xt[0].IsZero(hashLen)); - for (size_t l = 0; l < j - 1; l++) { - for (size_t m = l + 1; m < j; m++) { - // We truncated, so don't check for distinct indices here - TruncatedStepRow Xi {Xt[i+l], Xt[i+m], - hashLen, lenIndices, - CollisionByteLength}; - if (!(Xi.IsZero(hashLen-CollisionByteLength) && - IsProbablyDuplicate(Xi.GetTruncatedIndices(hashLen-CollisionByteLength, 2*lenIndices), - 2*lenIndices))) { - Xc.emplace_back(Xi); - } - } - } - - // 2d) Store tuples on the table in-place if possible - while (posFree < i+j && Xc.size() > 0) { - Xt[posFree++] = Xc.back(); - Xc.pop_back(); - } - - i += j; - if (cancelled(ListColliding)) throw solver_cancelled; - } - - // 2e) Handle edge case where final table entry has no collision - while (posFree < Xt.size() && Xc.size() > 0) { - Xt[posFree++] = Xc.back(); - Xc.pop_back(); - } - - if (Xc.size() > 0) { - // 2f) Add overflow to end of table - Xt.insert(Xt.end(), Xc.begin(), Xc.end()); - } else if (posFree < Xt.size()) { - // 2g) Remove empty space at the end - Xt.erase(Xt.begin()+posFree, Xt.end()); - Xt.shrink_to_fit(); - } - - hashLen -= CollisionByteLength; - lenIndices *= 2; - if (cancelled(RoundEnd)) throw solver_cancelled; - } - - // k+1) Find a collision on last 2n(k+1) bits - if (Xt.size() > 1) { - std::sort(Xt.begin(), Xt.end(), CompareSR(hashLen)); - if (cancelled(FinalSorting)) throw solver_cancelled; - size_t i = 0; - while (i < Xt.size() - 1) { - size_t j = 1; - while (i+j < Xt.size() && - HasCollision(Xt[i], Xt[i+j], hashLen)) { - j++; - } - - for (size_t l = 0; l < j - 1; l++) { - for (size_t m = l + 1; m < j; m++) { - TruncatedStepRow res(Xt[i+l], Xt[i+m], - hashLen, lenIndices, 0); - auto soln = res.GetTruncatedIndices(hashLen, 2*lenIndices); - if (!IsProbablyDuplicate(soln, 2*lenIndices)) { - partialSolns.push_back(soln); - } - } - } - - i += j; - if (cancelled(FinalColliding)) throw solver_cancelled; - } - } - - } // Ensure Xt goes out of scope and is destroyed - - - // Now for each solution run the algorithm again to recreate the indices - for (std::shared_ptr partialSoln : partialSolns) { - std::set> solns; - size_t hashLen; - size_t lenIndices; - unsigned char tmpHash[HashOutput]; - std::vector>>> X; - X.reserve(K+1); - - // 3) Repeat steps 1 and 2 for each partial index - for (eh_index i = 0; i < soln_size; i++) { - // 1) Generate first list of possibilities - std::vector> icv; - icv.reserve(recreate_size); - for (eh_index j = 0; j < recreate_size; j++) { - eh_index newIndex { UntruncateIndex(partialSoln.get()[i], j, CollisionBitLength + 1) }; - if (j == 0 || newIndex % IndicesPerHashOutput == 0) { - GenerateHash(base_state, newIndex/IndicesPerHashOutput, - tmpHash, HashOutput, N, R); - } - icv.emplace_back(tmpHash+((newIndex % IndicesPerHashOutput) * GetSizeInBytes(N)), - GetSizeInBytes(N), HashLength, CollisionBitLength, newIndex); - if (cancelled(PartialGeneration)) throw solver_cancelled; - } - boost::optional>> ic = icv; - - // 2a) For each pair of lists: - hashLen = HashLength; - lenIndices = sizeof(eh_index); - size_t rti = i; - for (size_t r = 0; r <= K; r++) { - // 2b) Until we are at the top of a subtree: - if (r < X.size()) { - if (X[r]) { - // 2c) Merge the lists - ic->reserve(ic->size() + X[r]->size()); - ic->insert(ic->end(), X[r]->begin(), X[r]->end()); - std::sort(ic->begin(), ic->end(), CompareSR(hashLen)); - if (cancelled(PartialSorting)) throw solver_cancelled; - size_t lti = rti-(static_cast(1)<size() == 0) - goto invalidsolution; - - X[r] = boost::none; - hashLen -= CollisionByteLength; - lenIndices *= 2; - rti = lti; - } else { - X[r] = *ic; - break; - } - } else { - X.push_back(ic); - break; - } - if (cancelled(PartialSubtreeEnd)) throw solver_cancelled; - } - if (cancelled(PartialIndexEnd)) throw solver_cancelled; - } - - // We are at the top of the tree - assert(X.size() == K+1); - for (FullStepRow row : *X[K]) { - auto soln = row.GetIndices(hashLen, lenIndices, CollisionBitLength); - assert(soln.size() == beamhash_solution_size(N, K)); - solns.insert(soln); - } - for (auto soln : solns) { - if (validBlock(soln)) - return true; - } - if (cancelled(PartialEnd)) throw solver_cancelled; - continue; - -invalidsolution: - invalidCount++; - } - - return false; -} -#endif // ENABLE_MINING - -template -bool EquihashR::IsValidSolution(const eh_HashState& base_state, std::vector soln) -{ - if (soln.size() != SolutionWidth) { - return false; - } - - std::vector> X; - X.reserve(1 << K); - unsigned char tmpHash[HashOutput]; - for (eh_index i : GetIndicesFromMinimal(soln, CollisionBitLength)) { - if (i >= (1U << (CollisionBitLength + 1 - R))) { - return false; - } - GenerateHash(base_state, i/IndicesPerHashOutput, tmpHash, HashOutput, N, R); - X.emplace_back(tmpHash+((i % IndicesPerHashOutput) * GetSizeInBytes(N)), - GetSizeInBytes(N), HashLength, CollisionBitLength, i); - } - - size_t hashLen = HashLength; - size_t lenIndices = sizeof(eh_index); - while (X.size() > 1) { - std::vector> Xc; - for (size_t i = 0; i < X.size(); i += 2) { - if (!HasCollision(X[i], X[i+1], CollisionByteLength)) { - return false; - } - if (X[i+1].IndicesBefore(X[i], hashLen, lenIndices)) { - return false; - } - if (!DistinctIndices(X[i], X[i+1], hashLen, lenIndices)) { - return false; - } - Xc.emplace_back(X[i], X[i+1], hashLen, lenIndices, CollisionByteLength); - } - X = Xc; - hashLen -= CollisionByteLength; - lenIndices *= 2; - } - - assert(X.size() == 1); - return X[0].IsZero(hashLen); -} - -// Explicit instantiations for BeamHashI -template int EquihashR<150,5,0>::InitialiseState(eh_HashState& base_state); -template bool EquihashR<150,5,0>::IsValidSolution(const eh_HashState& base_state, std::vector soln); -#ifdef ENABLE_MINING -template bool EquihashR<150,5,0>::OptimisedSolve(const eh_HashState& base_state, - const std::function&)> validBlock, - const std::function cancelled); -#endif - - -// Explicit instantiations for BeamHashII -template int EquihashR<150,5,3>::InitialiseState(eh_HashState& base_state); -template bool EquihashR<150,5,3>::IsValidSolution(const eh_HashState& base_state, std::vector soln); -#ifdef ENABLE_MINING -template bool EquihashR<150,5,3>::OptimisedSolve(const eh_HashState& base_state, - const std::function&)> validBlock, - const std::function cancelled); -#endif - diff --git a/src/Native/libbeamhash/crypto/equihashR.h b/src/Native/libbeamhash/crypto/equihashR.h deleted file mode 100644 index fd0baa045c..0000000000 --- a/src/Native/libbeamhash/crypto/equihashR.h +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright (c) 2019 The Beam Team - -// Based on Reference Implementation of the Equihash Proof-of-Work algorithm. -// Copyright (c) 2016 Jack Grigg -// Copyright (c) 2016 The Zcash developers - -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -// Resources: -// Alex Biryukov and Dmitry Khovratovich -// Equihash: Asymmetric Proof-of-Work Based on the Generalized Birthday Problem -// NDSS ’16, 21-24 February 2016, San Diego, CA, USA -// https://www.internetsociety.org/sites/default/files/blogs-media/equihash-asymmetric-proof-of-work-based-generalized-birthday-problem.pdf - -#ifndef EQUIHASHR_H -#define EQUIHASHR_H - -#if defined(__ANDROID__) || !defined(BEAM_USE_AVX) -#include "blake/ref/blake2.h" -#else -#include "blake/sse/blake2.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "powScheme.h" - -typedef blake2b_state eh_HashState; -typedef uint32_t eh_index; -typedef uint8_t eh_trunc; - -void ExpandArray(const unsigned char* in, size_t in_len, - unsigned char* out, size_t out_len, - size_t bit_len, size_t byte_pad=0); -void CompressArray(const unsigned char* in, size_t in_len, - unsigned char* out, size_t out_len, - size_t bit_len, size_t byte_pad=0); - -eh_index ArrayToEhIndex(const unsigned char* array); -eh_trunc TruncateIndex(const eh_index i, const unsigned int ilen); - -std::vector GetIndicesFromMinimal(std::vector minimal, - size_t cBitLen); -std::vector GetMinimalFromIndices(std::vector indices, - size_t cBitLen); - -template -class StepRow -{ - template - friend class StepRow; - friend class CompareSR; - -protected: - unsigned char hash[WIDTH]; - -public: - StepRow(const unsigned char* hashIn, size_t hInLen, - size_t hLen, size_t cBitLen); - ~StepRow() { } - - template - StepRow(const StepRow& a); - - bool IsZero(size_t len); - - template - friend bool HasCollision(StepRow& a, StepRow& b, size_t l); -}; - -class CompareSR -{ -private: - size_t len; - -public: - CompareSR(size_t l) : len {l} { } - - template - inline bool operator()(const StepRow& a, const StepRow& b) { return memcmp(a.hash, b.hash, len) < 0; } -}; - -template -bool HasCollision(StepRow& a, StepRow& b, size_t l); - -template -class FullStepRow : public StepRow -{ - template - friend class FullStepRow; - - using StepRow::hash; - -public: - FullStepRow(const unsigned char* hashIn, size_t hInLen, - size_t hLen, size_t cBitLen, eh_index i); - ~FullStepRow() { } - - FullStepRow(const FullStepRow& a) : StepRow {a} { } - template - FullStepRow(const FullStepRow& a, const FullStepRow& b, size_t len, size_t lenIndices, size_t trim); - FullStepRow& operator=(const FullStepRow& a); - - inline bool IndicesBefore(const FullStepRow& a, size_t len, size_t lenIndices) const { return memcmp(hash+len, a.hash+len, lenIndices) < 0; } - std::vector GetIndices(size_t len, size_t lenIndices, - size_t cBitLen) const; - - template - friend bool DistinctIndices(const FullStepRow& a, const FullStepRow& b, - size_t len, size_t lenIndices); - template - friend bool IsValidBranch(const FullStepRow& a, const size_t len, const unsigned int ilen, const eh_trunc t); -}; - -template -class TruncatedStepRow : public StepRow -{ - template - friend class TruncatedStepRow; - - using StepRow::hash; - -public: - TruncatedStepRow(const unsigned char* hashIn, size_t hInLen, - size_t hLen, size_t cBitLen, - eh_index i, unsigned int ilen); - ~TruncatedStepRow() { } - - TruncatedStepRow(const TruncatedStepRow& a) : StepRow {a} { } - template - TruncatedStepRow(const TruncatedStepRow& a, const TruncatedStepRow& b, size_t len, size_t lenIndices, int trim); - TruncatedStepRow& operator=(const TruncatedStepRow& a); - - inline bool IndicesBefore(const TruncatedStepRow& a, size_t len, size_t lenIndices) const { return memcmp(hash+len, a.hash+len, lenIndices) < 0; } - std::shared_ptr GetTruncatedIndices(size_t len, size_t lenIndices) const; -}; - - - -inline constexpr const size_t max(const size_t A, const size_t B) { return A > B ? A : B; } - -inline constexpr size_t beamhash_solution_size(unsigned int N, unsigned int K) { - return (1 << K)*(N/(K+1)+1)/8; -} - -constexpr uint8_t GetSizeInBytes(size_t N) -{ - return static_cast((N + 7) / 8); -} - - - -template -bool DistinctIndices(const FullStepRow& a, const FullStepRow& b, size_t len, size_t lenIndices) -{ - for(size_t i = 0; i < lenIndices; i += sizeof(eh_index)) { - for(size_t j = 0; j < lenIndices; j += sizeof(eh_index)) { - if (memcmp(a.hash+len+i, b.hash+len+j, sizeof(eh_index)) == 0) { - return false; - } - } - } - return true; -} - -template -bool IsProbablyDuplicate(std::shared_ptr indices, size_t lenIndices) -{ - bool checked_index[MAX_INDICES] = {false}; - size_t count_checked = 0; - for (size_t z = 0; z < lenIndices; z++) { - // Skip over indices we have already paired - if (!checked_index[z]) { - for (size_t y = z+1; y < lenIndices; y++) { - if (!checked_index[y] && indices.get()[z] == indices.get()[y]) { - // Pair found - checked_index[y] = true; - count_checked += 2; - break; - } - } - } - } - return count_checked == lenIndices; -} - -template -bool IsValidBranch(const FullStepRow& a, const size_t len, const unsigned int ilen, const eh_trunc t) -{ - return TruncateIndex(ArrayToEhIndex(a.hash+len), ilen) == t; -} - - - -template -class EquihashR : public PoWScheme -{ -private: - static_assert(K < N); - static_assert((N/(K+1)) + 1 < 8*sizeof(eh_index)); - -public: - enum : size_t { IndicesPerHashOutput=512/N }; - enum : size_t { HashOutput = IndicesPerHashOutput * GetSizeInBytes(N) }; - enum : size_t { CollisionBitLength=N/(K+1) }; - enum : size_t { CollisionByteLength=(CollisionBitLength+7)/8 }; - enum : size_t { HashLength=(K+1)*CollisionByteLength }; - enum : size_t { FullWidth=2*CollisionByteLength+sizeof(eh_index)*(1 << (K-1)) }; - enum : size_t { FinalFullWidth=2*CollisionByteLength+sizeof(eh_index)*(1 << (K)) }; - enum : size_t { TruncatedWidth=max(HashLength+sizeof(eh_trunc), 2*CollisionByteLength+sizeof(eh_trunc)*(1 << (K-1))) }; - enum : size_t { FinalTruncatedWidth=max(HashLength+sizeof(eh_trunc), 2*CollisionByteLength+sizeof(eh_trunc)*(1 << (K))) }; - enum : size_t { SolutionWidth=(1 << K)*(CollisionBitLength+1)/8 }; - - EquihashR() { } - - int InitialiseState(eh_HashState& base_state); - bool IsValidSolution(const eh_HashState& base_state, std::vector soln); -#ifdef ENABLE_MINING - bool OptimisedSolve(const eh_HashState& base_state, - const std::function&)> validBlock, - const std::function cancelled); -#endif -}; - -static EquihashR<150,5,0> BeamHashI; -static EquihashR<150,5,3> BeamHashII; - - -#define EhRInitialiseState(n, k, r, base_state) \ - if (n == 150 && k == 5 && r == 0) { \ - BeamHashI.InitialiseState(base_state); \ - } else if (n == 150 && k == 5 && r == 3)) { \ - BeamHashII.InitialiseState(base_state); \ - } else { \ - throw std::invalid_argument("Unsupported Equihash parameters"); \ - } - -#define EhRIsValidSolution(n, k, r, base_state, soln, ret) \ - if (n == 150 && k == 5 && r == 0) { \ - ret = BeamHashI.IsValidSolution(base_state, soln); \ - } else if (n == 150 && k == 5 && r == 3)) { \ - ret = BeamHashII.IsValidSolution(base_state, soln); \ - } else { \ - throw std::invalid_argument("Unsupported Equihash parameters"); \ - } - - -#endif diff --git a/src/Native/libbeamhash/crypto/sha256.h b/src/Native/libbeamhash/crypto/sha256.h deleted file mode 100644 index b9d0f64839..0000000000 --- a/src/Native/libbeamhash/crypto/sha256.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Sha256.h -- SHA-256 Hash -2016-11-04 : Marc Bevand : A few changes to make it more self-contained -2010-06-11 : Igor Pavlov : Public domain */ - -#ifndef __CRYPTO_SHA256_H -#define __CRYPTO_SHA256_H - -#define SHA256_DIGEST_SIZE 32 -#include - -typedef struct -{ - uint32_t state[8]; - uint64_t count; - uint8_t buffer[64]; -} CSha256; - -void Sha256_Init(CSha256 *p); -void Sha256_Update(CSha256 *p, const uint8_t *data, size_t size); -void Sha256_Final(CSha256 *p, uint8_t *digest); -void Sha256_Onestep(const uint8_t *data, size_t size, uint8_t *digest); - -#endif diff --git a/src/Native/libbeamhash/equihashR.h b/src/Native/libbeamhash/equihashR.h new file mode 100644 index 0000000000..502dba8870 --- /dev/null +++ b/src/Native/libbeamhash/equihashR.h @@ -0,0 +1,299 @@ +// Copyright (c) 2019 The Beam Team + +// Based on Reference Implementation of the Equihash Proof-of-Work algorithm. +// Copyright (c) 2016 Jack Grigg +// Copyright (c) 2016 The Zcash developers + +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// Resources: +// Alex Biryukov and Dmitry Khovratovich +// Equihash: Asymmetric Proof-of-Work Based on the Generalized Birthday Problem +// NDSS ’16, 21-24 February 2016, San Diego, CA, USA +// https://www.internetsociety.org/sites/default/files/blogs-media/equihash-asymmetric-proof-of-work-based-generalized-birthday-problem.pdf + +#ifndef EQUIHASHR_H +#define EQUIHASHR_H + +#include "blake/blake2.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "powScheme.h" + +typedef blake2b_state eh_HashState; +typedef uint32_t eh_index; +typedef uint8_t eh_trunc; + +void ExpandArray(const unsigned char* in, size_t in_len, + unsigned char* out, size_t out_len, + size_t bit_len, size_t byte_pad = 0); +void CompressArray(const unsigned char* in, size_t in_len, + unsigned char* out, size_t out_len, + size_t bit_len, size_t byte_pad = 0); + +eh_index ArrayToEhIndex(const unsigned char* array); +eh_trunc TruncateIndex(const eh_index i, const unsigned int ilen); + +std::vector GetIndicesFromMinimal(std::vector minimal, + size_t cBitLen); +std::vector GetMinimalFromIndices(std::vector indices, + size_t cBitLen); + +template +class StepRow +{ + template + friend class StepRow; + friend class CompareSR; + +protected: + unsigned char hash[WIDTH]; + +public: + StepRow(const unsigned char* hashIn, size_t hInLen, + size_t hLen, size_t cBitLen); + ~StepRow() {} + + template + StepRow(const StepRow& a); + + bool IsZero(size_t len); + + template + friend bool HasCollision(StepRow& a, StepRow& b, size_t l); +}; + +class CompareSR +{ +private: + size_t len; + +public: + CompareSR(size_t l) + : len{l} {} + + template + inline bool operator()(const StepRow& a, const StepRow& b) + { + return memcmp(a.hash, b.hash, len) < 0; + } +}; + +template +bool HasCollision(StepRow& a, StepRow& b, size_t l); + +template +class FullStepRow : public StepRow +{ + template + friend class FullStepRow; + + using StepRow::hash; + +public: + FullStepRow(const unsigned char* hashIn, size_t hInLen, + size_t hLen, size_t cBitLen, eh_index i); + ~FullStepRow() {} + + FullStepRow(const FullStepRow& a) + : StepRow{a} {} + template + FullStepRow(const FullStepRow& a, const FullStepRow& b, size_t len, size_t lenIndices, size_t trim); + FullStepRow& operator=(const FullStepRow& a); + + inline bool IndicesBefore(const FullStepRow& a, size_t len, size_t lenIndices) const { return memcmp(hash + len, a.hash + len, lenIndices) < 0; } + std::vector GetIndices(size_t len, size_t lenIndices, + size_t cBitLen) const; + + template + friend bool DistinctIndices(const FullStepRow& a, const FullStepRow& b, + size_t len, size_t lenIndices); + template + friend bool IsValidBranch(const FullStepRow& a, const size_t len, const unsigned int ilen, const eh_trunc t); +}; + +template +class TruncatedStepRow : public StepRow +{ + template + friend class TruncatedStepRow; + + using StepRow::hash; + +public: + TruncatedStepRow(const unsigned char* hashIn, size_t hInLen, + size_t hLen, size_t cBitLen, + eh_index i, unsigned int ilen); + ~TruncatedStepRow() {} + + TruncatedStepRow(const TruncatedStepRow& a) + : StepRow{a} {} + template + TruncatedStepRow(const TruncatedStepRow& a, const TruncatedStepRow& b, size_t len, size_t lenIndices, int trim); + TruncatedStepRow& operator=(const TruncatedStepRow& a); + + inline bool IndicesBefore(const TruncatedStepRow& a, size_t len, size_t lenIndices) const { return memcmp(hash + len, a.hash + len, lenIndices) < 0; } + std::shared_ptr GetTruncatedIndices(size_t len, size_t lenIndices) const; +}; + + +inline constexpr const size_t max(const size_t A, const size_t B) +{ + return A > B ? A : B; +} + +inline constexpr size_t beamhash_solution_size(unsigned int N, unsigned int K) +{ + return (1 << K) * (N / (K + 1) + 1) / 8; +} + +constexpr uint8_t GetSizeInBytes(size_t N) +{ + return static_cast((N + 7) / 8); +} + + +template +bool DistinctIndices(const FullStepRow& a, const FullStepRow& b, size_t len, size_t lenIndices) +{ + for (size_t i = 0; i < lenIndices; i += sizeof(eh_index)) + { + for (size_t j = 0; j < lenIndices; j += sizeof(eh_index)) + { + if (memcmp(a.hash + len + i, b.hash + len + j, sizeof(eh_index)) == 0) + { + return false; + } + } + } + return true; +} + +template +bool IsProbablyDuplicate(std::shared_ptr indices, size_t lenIndices) +{ + bool checked_index[MAX_INDICES] = {false}; + size_t count_checked = 0; + for (size_t z = 0; z < lenIndices; z++) + { + // Skip over indices we have already paired + if (!checked_index[z]) + { + for (size_t y = z + 1; y < lenIndices; y++) + { + if (!checked_index[y] && indices.get()[z] == indices.get()[y]) + { + // Pair found + checked_index[y] = true; + count_checked += 2; + break; + } + } + } + } + return count_checked == lenIndices; +} + +template +bool IsValidBranch(const FullStepRow& a, const size_t len, const unsigned int ilen, const eh_trunc t) +{ + return TruncateIndex(ArrayToEhIndex(a.hash + len), ilen) == t; +} + + +template +class EquihashR : public PoWScheme +{ +public: + enum : size_t + { + IndicesPerHashOutput = 512 / N + }; + enum : size_t + { + HashOutput = IndicesPerHashOutput * GetSizeInBytes(N) + }; + enum : size_t + { + CollisionBitLength = N / (K + 1) + }; + enum : size_t + { + CollisionByteLength = (CollisionBitLength + 7) / 8 + }; + enum : size_t + { + HashLength = (K + 1) * CollisionByteLength + }; + enum : size_t + { + FullWidth = 2 * CollisionByteLength + sizeof(eh_index) * (1 << (K - 1)) + }; + enum : size_t + { + FinalFullWidth = 2 * CollisionByteLength + sizeof(eh_index) * (1 << (K)) + }; + enum : size_t + { + TruncatedWidth = max(HashLength + sizeof(eh_trunc), 2 * CollisionByteLength + sizeof(eh_trunc) * (1 << (K - 1))) + }; + enum : size_t + { + FinalTruncatedWidth = max(HashLength + sizeof(eh_trunc), 2 * CollisionByteLength + sizeof(eh_trunc) * (1 << (K))) + }; + enum : size_t + { + SolutionWidth = (1 << K) * (CollisionBitLength + 1) / 8 + }; + + EquihashR() {} + + int InitialiseState(eh_HashState& base_state); + bool IsValidSolution(const eh_HashState& base_state, std::vector soln); + bool OptimisedSolve(const eh_HashState& base_state, + const std::function&)> validBlock, + const std::function cancelled); +}; + +static EquihashR<150, 5, 0> BeamHashI; +static EquihashR<150, 5, 3> BeamHashII; + + +#define EhRInitialiseState(n, k, r, base_state) \ + if (n == 150 && k == 5 && r == 0) \ + { \ + BeamHashI.InitialiseState(base_state); \ + } \ + else if (n == 150 && k == 5 && r == 3) \ + { \ + BeamHashII.InitialiseState(base_state); \ + } \ + else \ + { \ + throw std::invalid_argument("Unsupported Equihash parameters"); \ + } + +#define EhRIsValidSolution(n, k, r, base_state, soln, ret) \ + if (n == 150 && k == 5 && r == 0) \ + { \ + ret = BeamHashI.IsValidSolution(base_state, soln); \ + } \ + else if (n == 150 && k == 5 && r == 3) \ + { \ + ret = BeamHashII.IsValidSolution(base_state, soln); \ + } \ + else \ + { \ + throw std::invalid_argument("Unsupported Equihash parameters"); \ + } + + +#endif \ No newline at end of file diff --git a/src/Native/libbeamhash/equihashR_imp.cpp b/src/Native/libbeamhash/equihashR_imp.cpp new file mode 100644 index 0000000000..30c191d1f4 --- /dev/null +++ b/src/Native/libbeamhash/equihashR_imp.cpp @@ -0,0 +1,785 @@ +// Copyright (c) 2019 The Beam Team + +// Based on Reference Implementation of the Equihash Proof-of-Work algorithm. +// Copyright (c) 2016 Jack Grigg +// Copyright (c) 2016 The Zcash developers + +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// Resources: +// Alex Biryukov and Dmitry Khovratovich +// Equihash: Asymmetric Proof-of-Work Based on the Generalized Birthday Problem +// NDSS ’16, 21-24 February 2016, San Diego, CA, USA +// https://www.internetsociety.org/sites/default/files/blogs-media/equihash-asymmetric-proof-of-work-based-generalized-birthday-problem.pdf + +#include "compat/endian.h" +#include "equihashR.h" +//#include "util.h" + +#include +#include +#include +#include + +SolverCancelledException solver_cancelled; + +namespace +{ + void ZeroizeUnusedBits(size_t N, size_t R, unsigned char* hash, size_t hLen) + { + uint8_t rem = N % 8; + const size_t step = GetSizeInBytes(N); + + if (rem) + { + // clear lowest 8-rem bits + for (size_t i = step - 1; i < hLen; i += step) + { + uint8_t b = 0xff << (8 - rem); + hash[i] &= b; + } + } + + if (R) + { + for (size_t i = 0; i < hLen; i += step) + { + uint8_t b = 0xff >> (2 * R); + hash[i] &= b; + } + } + } +} // namespace + +template +int EquihashR::InitialiseState(eh_HashState& base_state) +{ + uint32_t le_N = htole32(N); + uint32_t le_K = htole32(K); + + unsigned char personalization[BLAKE2B_PERSONALBYTES] = {}; + memcpy(personalization, "Beam-PoW", 8); + memcpy(personalization + 8, &le_N, 4); + memcpy(personalization + 12, &le_K, 4); + + const uint8_t outlen = (512 / N) * GetSizeInBytes(N); + + // static_assert(!((!outlen) || (outlen > BLAKE2B_OUTBYTES))); + + blake2b_param param = {0}; + param.digest_length = outlen; + param.fanout = 1; + param.depth = 1; + + memcpy(¶m.personal, personalization, BLAKE2B_PERSONALBYTES); + + return blake2b_init_param(&base_state, ¶m); +} + +void GenerateHash(const eh_HashState& base_state, eh_index g, + unsigned char* hash, size_t hLen, size_t N, size_t R) +{ + uint32_t myHash[16] = {0}; + uint32_t startIndex = g & 0xFFFFFFF0; + + for (uint32_t g2 = startIndex; g2 <= g; g2++) + { + uint32_t tmpHash[16] = {0}; + + eh_HashState state; + state = base_state; + eh_index lei = htole32(g2); + blake2b_update(&state, (const unsigned char*)&lei, + sizeof(eh_index)); + + blake2b_final(&state, (unsigned char*)&tmpHash[0], static_cast(hLen)); + + for (uint32_t idx = 0; idx < 16; idx++) + myHash[idx] += tmpHash[idx]; + } + + memcpy(hash, &myHash[0], hLen); + ZeroizeUnusedBits(N, R, hash, hLen); +} + +void ExpandArray(const unsigned char* in, size_t in_len, + unsigned char* out, size_t out_len, + size_t bit_len, size_t byte_pad) +{ + assert(bit_len >= 8); + assert(8 * sizeof(uint32_t) >= bit_len); + + size_t out_width{(bit_len + 7) / 8 + byte_pad}; + assert(out_len == 8 * out_width * in_len / bit_len); + + uint32_t bit_len_mask{((uint32_t)1 << bit_len) - 1}; + + // The acc_bits least-significant bits of acc_value represent a bit sequence + // in big-endian order. + size_t acc_bits = 0; + uint32_t acc_value = 0; + + size_t j = 0; + for (size_t i = 0; i < in_len; i++) + { + acc_value = (acc_value << 8) | in[i]; + acc_bits += 8; + + // When we have bit_len or more bits in the accumulator, write the next + // output element. + if (acc_bits >= bit_len) + { + acc_bits -= bit_len; + for (size_t x = 0; x < byte_pad; x++) + { + out[j + x] = 0; + } + for (size_t x = byte_pad; x < out_width; x++) + { + out[j + x] = ( + // Big-endian + acc_value >> (acc_bits + (8 * (out_width - x - 1)))) & + ( + // Apply bit_len_mask across byte boundaries + (bit_len_mask >> (8 * (out_width - x - 1))) & 0xFF); + } + j += out_width; + } + } +} + +void CompressArray(const unsigned char* in, size_t in_len, + unsigned char* out, size_t out_len, + size_t bit_len, size_t byte_pad) +{ + assert(bit_len >= 8); + assert(8 * sizeof(uint32_t) >= bit_len); + + size_t in_width{(bit_len + 7) / 8 + byte_pad}; + assert(out_len == (bit_len * in_len / in_width + 7) / 8); + + uint32_t bit_len_mask{((uint32_t)1 << bit_len) - 1}; + + // The acc_bits least-significant bits of acc_value represent a bit sequence + // in big-endian order. + size_t acc_bits = 0; + uint32_t acc_value = 0; + + size_t j = 0; + for (size_t i = 0; i < out_len; i++) + { + // When we have fewer than 8 bits left in the accumulator, read the next + // input element. + if (acc_bits < 8) + { + if (j < in_len) + { + acc_value = acc_value << bit_len; + for (size_t x = byte_pad; x < in_width; x++) + { + acc_value = acc_value | (( + // Apply bit_len_mask across byte boundaries + in[j + x] & ((bit_len_mask >> (8 * (in_width - x - 1))) & 0xFF)) + << (8 * (in_width - x - 1))); // Big-endian + } + j += in_width; + acc_bits += bit_len; + } + else + { + acc_value <<= 8 - acc_bits; + acc_bits += 8 - acc_bits; + ; + } + } + + acc_bits -= 8; + out[i] = (acc_value >> acc_bits) & 0xFF; + } +} + +// Big-endian so that lexicographic array comparison is equivalent to integer +// comparison +void EhIndexToArray(const eh_index i, unsigned char* array) +{ + // static_assert(sizeof(eh_index) == 4); + eh_index bei = htobe32(i); + memcpy(array, &bei, sizeof(eh_index)); +} + +// Big-endian so that lexicographic array comparison is equivalent to integer +// comparison +eh_index ArrayToEhIndex(const unsigned char* array) +{ + // static_assert(sizeof(eh_index) == 4); + eh_index bei; + memcpy(&bei, array, sizeof(eh_index)); + return be32toh(bei); +} + +eh_trunc TruncateIndex(const eh_index i, const unsigned int ilen) +{ + // Truncate to 8 bits + // static_assert(sizeof(eh_trunc) == 1); + return (i >> (ilen - 8)) & 0xff; +} + +eh_index UntruncateIndex(const eh_trunc t, const eh_index r, const unsigned int ilen) +{ + eh_index i{t}; + return (i << (ilen - 8)) | r; +} + +std::vector GetIndicesFromMinimal(std::vector minimal, + size_t cBitLen) +{ + assert(((cBitLen + 1) + 7) / 8 <= sizeof(eh_index)); + size_t lenIndices{8 * sizeof(eh_index) * minimal.size() / (cBitLen + 1)}; + size_t bytePad{sizeof(eh_index) - ((cBitLen + 1) + 7) / 8}; + std::vector array(lenIndices); + ExpandArray(minimal.data(), minimal.size(), + array.data(), lenIndices, cBitLen + 1, bytePad); + std::vector ret; + for (size_t i = 0; i < lenIndices; i += sizeof(eh_index)) + { + ret.push_back(ArrayToEhIndex(array.data() + i)); + } + return ret; +} + +std::vector GetMinimalFromIndices(std::vector indices, + size_t cBitLen) +{ + assert(((cBitLen + 1) + 7) / 8 <= sizeof(eh_index)); + size_t lenIndices{indices.size() * sizeof(eh_index)}; + size_t minLen{(cBitLen + 1) * lenIndices / (8 * sizeof(eh_index))}; + size_t bytePad{sizeof(eh_index) - ((cBitLen + 1) + 7) / 8}; + std::vector array(lenIndices); + for (size_t i = 0; i < indices.size(); i++) + { + EhIndexToArray(indices[i], array.data() + (i * sizeof(eh_index))); + } + std::vector ret(minLen); + CompressArray(array.data(), lenIndices, + ret.data(), minLen, cBitLen + 1, bytePad); + return ret; +} + +template +StepRow::StepRow(const unsigned char* hashIn, size_t hInLen, + size_t hLen, size_t cBitLen) +{ + assert(hLen <= WIDTH); + ExpandArray(hashIn, hInLen, hash, hLen, cBitLen); +} + +template +template +StepRow::StepRow(const StepRow& a) +{ + // static_assert(W <= WIDTH); + std::copy(a.hash, a.hash + W, hash); +} + +template +FullStepRow::FullStepRow(const unsigned char* hashIn, size_t hInLen, + size_t hLen, size_t cBitLen, eh_index i) + : StepRow{hashIn, hInLen, hLen, cBitLen} +{ + EhIndexToArray(i, hash + hLen); +} + +template +template +FullStepRow::FullStepRow(const FullStepRow& a, const FullStepRow& b, size_t len, size_t lenIndices, size_t trim) + : StepRow{a} +{ + assert(len + lenIndices <= W); + assert(len - trim + (2 * lenIndices) <= WIDTH); + for (size_t i = trim; i < len; i++) + hash[i - trim] = a.hash[i] ^ b.hash[i]; + if (a.IndicesBefore(b, len, lenIndices)) + { + std::copy(a.hash + len, a.hash + len + lenIndices, hash + len - trim); + std::copy(b.hash + len, b.hash + len + lenIndices, hash + len - trim + lenIndices); + } + else + { + std::copy(b.hash + len, b.hash + len + lenIndices, hash + len - trim); + std::copy(a.hash + len, a.hash + len + lenIndices, hash + len - trim + lenIndices); + } +} + +template +FullStepRow& FullStepRow::operator=(const FullStepRow& a) +{ + std::copy(a.hash, a.hash + WIDTH, hash); + return *this; +} + +template +bool StepRow::IsZero(size_t len) +{ + // This doesn't need to be constant time. + for (size_t i = 0; i < len; i++) + { + if (hash[i] != 0) + return false; + } + return true; +} + +template +std::vector FullStepRow::GetIndices(size_t len, size_t lenIndices, + size_t cBitLen) const +{ + assert(((cBitLen + 1) + 7) / 8 <= sizeof(eh_index)); + size_t minLen{(cBitLen + 1) * lenIndices / (8 * sizeof(eh_index))}; + size_t bytePad{sizeof(eh_index) - ((cBitLen + 1) + 7) / 8}; + std::vector ret(minLen); + CompressArray(hash + len, lenIndices, ret.data(), minLen, cBitLen + 1, bytePad); + return ret; +} + +template +bool HasCollision(StepRow& a, StepRow& b, size_t l) +{ + // This doesn't need to be constant time. + for (size_t j = 0; j < l; j++) + { + if (a.hash[j] != b.hash[j]) + return false; + } + return true; +} + +template +TruncatedStepRow::TruncatedStepRow(const unsigned char* hashIn, size_t hInLen, + size_t hLen, size_t cBitLen, + eh_index i, unsigned int ilen) + : StepRow{hashIn, hInLen, hLen, cBitLen} +{ + hash[hLen] = TruncateIndex(i, ilen); +} + +template +template +TruncatedStepRow::TruncatedStepRow(const TruncatedStepRow& a, const TruncatedStepRow& b, size_t len, size_t lenIndices, int trim) + : StepRow{a} +{ + assert(len + lenIndices <= W); + assert(len - trim + (2 * lenIndices) <= WIDTH); + for (size_t i = static_cast(trim); i < len; i++) + hash[i - trim] = a.hash[i] ^ b.hash[i]; + if (a.IndicesBefore(b, len, lenIndices)) + { + std::copy(a.hash + len, a.hash + len + lenIndices, hash + len - trim); + std::copy(b.hash + len, b.hash + len + lenIndices, hash + len - trim + lenIndices); + } + else + { + std::copy(b.hash + len, b.hash + len + lenIndices, hash + len - trim); + std::copy(a.hash + len, a.hash + len + lenIndices, hash + len - trim + lenIndices); + } +} + +template +TruncatedStepRow& TruncatedStepRow::operator=(const TruncatedStepRow& a) +{ + std::copy(a.hash, a.hash + WIDTH, hash); + return *this; +} + +template +std::shared_ptr TruncatedStepRow::GetTruncatedIndices(size_t len, size_t lenIndices) const +{ + std::shared_ptr p(new eh_trunc[lenIndices], std::default_delete()); + std::copy(hash + len, hash + len + lenIndices, p.get()); + return p; +} + +template +void CollideBranches(std::vector>& X, const size_t hlen, const size_t lenIndices, const unsigned int clen, const unsigned int ilen, const eh_trunc lt, const eh_trunc rt) +{ + size_t i = 0; + size_t posFree = 0; + assert(X.size() > 0); + std::vector> Xc; + while (i < X.size() - 1) + { + // 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits + size_t j = 1; + while (i + j < X.size() && + HasCollision(X[i], X[i + j], clen)) + { + j++; + } + + // 2c) Calculate tuples (X_i ^ X_j, (i, j)) + for (size_t l = 0; l < j - 1; l++) + { + for (size_t m = l + 1; m < j; m++) + { + if (DistinctIndices(X[i + l], X[i + m], hlen, lenIndices)) + { + if (IsValidBranch(X[i + l], hlen, ilen, lt) && IsValidBranch(X[i + m], hlen, ilen, rt)) + { + Xc.emplace_back(X[i + l], X[i + m], hlen, lenIndices, clen); + } + else if (IsValidBranch(X[i + m], hlen, ilen, lt) && IsValidBranch(X[i + l], hlen, ilen, rt)) + { + Xc.emplace_back(X[i + m], X[i + l], hlen, lenIndices, clen); + } + } + } + } + + // 2d) Store tuples on the table in-place if possible + while (posFree < i + j && Xc.size() > 0) + { + X[posFree++] = Xc.back(); + Xc.pop_back(); + } + + i += j; + } + + // 2e) Handle edge case where final table entry has no collision + while (posFree < X.size() && Xc.size() > 0) + { + X[posFree++] = Xc.back(); + Xc.pop_back(); + } + + if (Xc.size() > 0) + { + // 2f) Add overflow to end of table + X.insert(X.end(), Xc.begin(), Xc.end()); + } + else if (posFree < X.size()) + { + // 2g) Remove empty space at the end + X.erase(X.begin() + posFree, X.end()); + X.shrink_to_fit(); + } +} + +template +bool EquihashR::OptimisedSolve(const eh_HashState& base_state, + const std::function&)> validBlock, + const std::function cancelled) +{ + eh_index init_size{1U << (CollisionBitLength + 1 - R)}; + eh_index recreate_size{UntruncateIndex(1, 0, CollisionBitLength + 1)}; + + // First run the algorithm with truncated indices + + const eh_index soln_size{1 << K}; + std::vector> partialSolns; + int invalidCount = 0; + { + // 1) Generate first list + size_t hashLen = HashLength; + size_t lenIndices = sizeof(eh_trunc); + std::vector> Xt; + Xt.reserve(init_size); + unsigned char tmpHash[HashOutput]; + for (eh_index g = 0; Xt.size() < init_size; g++) + { + GenerateHash(base_state, g, tmpHash, HashOutput, N, R); + for (eh_index i = 0; i < IndicesPerHashOutput && Xt.size() < init_size; i++) + { + Xt.emplace_back(tmpHash + (i * GetSizeInBytes(N)), GetSizeInBytes(N), HashLength, CollisionBitLength, + static_cast(g * IndicesPerHashOutput) + i, static_cast(CollisionBitLength + 1)); + } + if (cancelled(ListGeneration)) + throw solver_cancelled; + } + + // 3) Repeat step 2 until 2n/(k+1) bits remain + for (unsigned int r = 1; r < K && Xt.size() > 0; r++) + { + // 2a) Sort the list + std::sort(Xt.begin(), Xt.end(), CompareSR(CollisionByteLength)); + if (cancelled(ListSorting)) + throw solver_cancelled; + + size_t i = 0; + size_t posFree = 0; + std::vector> Xc; + while (i < Xt.size() - 1) + { + // 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits + size_t j = 1; + while (i + j < Xt.size() && + HasCollision(Xt[i], Xt[i + j], CollisionByteLength)) + { + j++; + } + + // 2c) Calculate tuples (X_i ^ X_j, (i, j)) + // bool checking_for_zero = (i == 0 && Xt[0].IsZero(hashLen)); + for (size_t l = 0; l < j - 1; l++) + { + for (size_t m = l + 1; m < j; m++) + { + // We truncated, so don't check for distinct indices here + TruncatedStepRow Xi{Xt[i + l], Xt[i + m], + hashLen, lenIndices, + CollisionByteLength}; + if (!(Xi.IsZero(hashLen - CollisionByteLength) && + IsProbablyDuplicate(Xi.GetTruncatedIndices(hashLen - CollisionByteLength, 2 * lenIndices), + 2 * lenIndices))) + { + Xc.emplace_back(Xi); + } + } + } + + // 2d) Store tuples on the table in-place if possible + while (posFree < i + j && Xc.size() > 0) + { + Xt[posFree++] = Xc.back(); + Xc.pop_back(); + } + + i += j; + if (cancelled(ListColliding)) + throw solver_cancelled; + } + + // 2e) Handle edge case where final table entry has no collision + while (posFree < Xt.size() && Xc.size() > 0) + { + Xt[posFree++] = Xc.back(); + Xc.pop_back(); + } + + if (Xc.size() > 0) + { + // 2f) Add overflow to end of table + Xt.insert(Xt.end(), Xc.begin(), Xc.end()); + } + else if (posFree < Xt.size()) + { + // 2g) Remove empty space at the end + Xt.erase(Xt.begin() + posFree, Xt.end()); + Xt.shrink_to_fit(); + } + + hashLen -= CollisionByteLength; + lenIndices *= 2; + if (cancelled(RoundEnd)) + throw solver_cancelled; + } + + // k+1) Find a collision on last 2n(k+1) bits + if (Xt.size() > 1) + { + std::sort(Xt.begin(), Xt.end(), CompareSR(hashLen)); + if (cancelled(FinalSorting)) + throw solver_cancelled; + size_t i = 0; + while (i < Xt.size() - 1) + { + size_t j = 1; + while (i + j < Xt.size() && + HasCollision(Xt[i], Xt[i + j], hashLen)) + { + j++; + } + + for (size_t l = 0; l < j - 1; l++) + { + for (size_t m = l + 1; m < j; m++) + { + TruncatedStepRow res(Xt[i + l], Xt[i + m], + hashLen, lenIndices, 0); + auto soln = res.GetTruncatedIndices(hashLen, 2 * lenIndices); + if (!IsProbablyDuplicate(soln, 2 * lenIndices)) + { + partialSolns.push_back(soln); + } + } + } + + i += j; + if (cancelled(FinalColliding)) + throw solver_cancelled; + } + } + + } // Ensure Xt goes out of scope and is destroyed + + + // Now for each solution run the algorithm again to recreate the indices + for (std::shared_ptr partialSoln : partialSolns) + { + std::set> solns; + size_t hashLen; + size_t lenIndices; + unsigned char tmpHash[HashOutput]; + std::vector>>> X; + X.reserve(K + 1); + + // 3) Repeat steps 1 and 2 for each partial index + for (eh_index i = 0; i < soln_size; i++) + { + // 1) Generate first list of possibilities + std::vector> icv; + icv.reserve(recreate_size); + for (eh_index j = 0; j < recreate_size; j++) + { + eh_index newIndex{UntruncateIndex(partialSoln.get()[i], j, CollisionBitLength + 1)}; + if (j == 0 || newIndex % IndicesPerHashOutput == 0) + { + GenerateHash(base_state, newIndex / IndicesPerHashOutput, + tmpHash, HashOutput, N, R); + } + icv.emplace_back(tmpHash + ((newIndex % IndicesPerHashOutput) * GetSizeInBytes(N)), + GetSizeInBytes(N), HashLength, CollisionBitLength, newIndex); + if (cancelled(PartialGeneration)) + throw solver_cancelled; + } + boost::optional>> ic = icv; + + // 2a) For each pair of lists: + hashLen = HashLength; + lenIndices = sizeof(eh_index); + size_t rti = i; + for (size_t r = 0; r <= K; r++) + { + // 2b) Until we are at the top of a subtree: + if (r < X.size()) + { + if (X[r]) + { + // 2c) Merge the lists + ic->reserve(ic->size() + X[r]->size()); + ic->insert(ic->end(), X[r]->begin(), X[r]->end()); + std::sort(ic->begin(), ic->end(), CompareSR(hashLen)); + if (cancelled(PartialSorting)) + throw solver_cancelled; + size_t lti = rti - (static_cast(1) << r); + CollideBranches(*ic, hashLen, lenIndices, + CollisionByteLength, + CollisionBitLength + 1, + partialSoln.get()[lti], partialSoln.get()[rti]); + + // 2d) Check if this has become an invalid solution + if (ic->size() == 0) + goto invalidsolution; + + X[r] = boost::none; + hashLen -= CollisionByteLength; + lenIndices *= 2; + rti = lti; + } + else + { + X[r] = *ic; + break; + } + } + else + { + X.push_back(ic); + break; + } + if (cancelled(PartialSubtreeEnd)) + throw solver_cancelled; + } + if (cancelled(PartialIndexEnd)) + throw solver_cancelled; + } + + // We are at the top of the tree + assert(X.size() == K + 1); + for (FullStepRow row : *X[K]) + { + auto soln = row.GetIndices(hashLen, lenIndices, CollisionBitLength); + assert(soln.size() == beamhash_solution_size(N, K)); + solns.insert(soln); + } + for (auto soln : solns) + { + if (validBlock(soln)) + return true; + } + if (cancelled(PartialEnd)) + throw solver_cancelled; + continue; + + invalidsolution: + invalidCount++; + } + + return false; +} + +template +bool EquihashR::IsValidSolution(const eh_HashState& base_state, std::vector soln) +{ + if (soln.size() != SolutionWidth) + { + return false; + } + + std::vector> X; + X.reserve(1 << K); + unsigned char tmpHash[HashOutput]; + for (eh_index i : GetIndicesFromMinimal(soln, CollisionBitLength)) + { + if (i >= (1U << (CollisionBitLength + 1 - R))) + { + return false; + } + GenerateHash(base_state, i / IndicesPerHashOutput, tmpHash, HashOutput, N, R); + X.emplace_back(tmpHash + ((i % IndicesPerHashOutput) * GetSizeInBytes(N)), + GetSizeInBytes(N), HashLength, CollisionBitLength, i); + } + + size_t hashLen = HashLength; + size_t lenIndices = sizeof(eh_index); + while (X.size() > 1) + { + std::vector> Xc; + for (size_t i = 0; i < X.size(); i += 2) + { + if (!HasCollision(X[i], X[i + 1], CollisionByteLength)) + { + return false; + } + if (X[i + 1].IndicesBefore(X[i], hashLen, lenIndices)) + { + return false; + } + if (!DistinctIndices(X[i], X[i + 1], hashLen, lenIndices)) + { + return false; + } + Xc.emplace_back(X[i], X[i + 1], hashLen, lenIndices, CollisionByteLength); + } + X = Xc; + hashLen -= CollisionByteLength; + lenIndices *= 2; + } + + assert(X.size() == 1); + return X[0].IsZero(hashLen); +} + +// Explicit instantiations for BeamHashI +template int EquihashR<150, 5, 0>::InitialiseState(eh_HashState& base_state); +template bool EquihashR<150, 5, 0>::IsValidSolution(const eh_HashState& base_state, std::vector soln); +template bool EquihashR<150, 5, 0>::OptimisedSolve(const eh_HashState& base_state, + const std::function&)> validBlock, + const std::function cancelled); + +// Explicit instantiations for BeamHashII +template int EquihashR<150, 5, 3>::InitialiseState(eh_HashState& base_state); +template bool EquihashR<150, 5, 3>::IsValidSolution(const eh_HashState& base_state, std::vector soln); +template bool EquihashR<150, 5, 3>::OptimisedSolve(const eh_HashState& base_state, + const std::function&)> validBlock, + const std::function cancelled); diff --git a/src/Native/libbeamhash/equihashR_imp.o b/src/Native/libbeamhash/equihashR_imp.o new file mode 100644 index 0000000000..32d3f9d893 Binary files /dev/null and b/src/Native/libbeamhash/equihashR_imp.o differ diff --git a/src/Native/libbeamhash/exports.cpp b/src/Native/libbeamhash/exports.cpp index ca1a49bb1f..a53229ccd9 100644 --- a/src/Native/libbeamhash/exports.cpp +++ b/src/Native/libbeamhash/exports.cpp @@ -25,15 +25,17 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. extern "C" MODULE_API bool beamhash_verify_export(const char* header, int header_length, const char* solution, int solution_length, const char* nonce, int nonce_length, int pow) { - if (header_length != 32) { + if (header_length != 32) + { return false; } - - if (nonce_length != 8) { + + if (nonce_length != 8) + { return false; } const std::vector vecSolution(solution, solution + solution_length); - + return verifyBH(header, nonce, vecSolution, pow); -} \ No newline at end of file +} diff --git a/src/Native/libbeamhash/exports.o b/src/Native/libbeamhash/exports.o new file mode 100644 index 0000000000..83d17c5777 Binary files /dev/null and b/src/Native/libbeamhash/exports.o differ diff --git a/src/Native/libbeamhash/libbeamhash.sln b/src/Native/libbeamhash/libbeamhash.sln index c6bae02c52..e5e2594e8e 100644 --- a/src/Native/libbeamhash/libbeamhash.sln +++ b/src/Native/libbeamhash/libbeamhash.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31229.75 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbeamhash", "libbeamhash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmultihash", "libbeamhash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/Native/libbeamhash/libbeamhash.vcxproj b/src/Native/libbeamhash/libbeamhash.vcxproj index 9ba7cea2ff..225fbd32af 100644 --- a/src/Native/libbeamhash/libbeamhash.vcxproj +++ b/src/Native/libbeamhash/libbeamhash.vcxproj @@ -168,57 +168,33 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - + + + + - - - - - - - - - - - - - + + + - - - - diff --git a/src/Native/libbeamhash/crypto/powScheme.h b/src/Native/libbeamhash/powScheme.h similarity index 58% rename from src/Native/libbeamhash/crypto/powScheme.h rename to src/Native/libbeamhash/powScheme.h index 8051ddc854..0622736f09 100644 --- a/src/Native/libbeamhash/crypto/powScheme.h +++ b/src/Native/libbeamhash/powScheme.h @@ -3,11 +3,8 @@ #ifndef POWSCHEME_H #define POWSCHEME_H -#if defined(__ANDROID__) || !defined(BEAM_USE_AVX) -#include "blake/ref/blake2.h" -#else -#include "blake/sse/blake2.h" -#endif +#include "blake/blake2.h" + enum SolverCancelCheck { @@ -27,23 +24,21 @@ enum SolverCancelCheck class SolverCancelledException : public std::exception { - virtual const char* what() const throw() { + virtual const char* what() const throw() + { return "BeamHash solver was cancelled"; } }; -class PoWScheme { +class PoWScheme +{ public: virtual int InitialiseState(blake2b_state& base_state) = 0; - virtual bool IsValidSolution(const blake2b_state& base_state, std::vector soln) = 0; - -#ifdef ENABLE_MINING + virtual bool IsValidSolution(const blake2b_state& base_state, std::vector soln) = 0; virtual bool OptimisedSolve(const blake2b_state& base_state, - const std::function&)> validBlock, - const std::function cancelled) = 0; -#endif - -}; + const std::function&)> validBlock, + const std::function cancelled) = 0; +}; -#endif +#endif \ No newline at end of file diff --git a/src/Native/libbeamhash/random.cpp b/src/Native/libbeamhash/random.cpp deleted file mode 100644 index 9fc6215ec8..0000000000 --- a/src/Native/libbeamhash/random.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "random.h" - -#include "support/cleanse.h" -#include "serialize.h" // for begin_ptr(vec) -#include "util.h" // for LogPrint() -#include "utilstrencodings.h" // for GetTime() - -#include - -#ifndef WIN32 -#include -#endif - -#include "sodium.h" - -static inline int64_t GetPerformanceCounter() -{ - int64_t nCounter = 0; -#ifdef WIN32 - QueryPerformanceCounter((LARGE_INTEGER*)&nCounter); -#else - timeval t; - gettimeofday(&t, NULL); - nCounter = (int64_t)(t.tv_sec * 1000000 + t.tv_usec); -#endif - return nCounter; -} - -void GetRandBytes(unsigned char* buf, size_t num) -{ - randombytes_buf(buf, num); -} - -uint64_t GetRand(uint64_t nMax) -{ - if (nMax == 0) - return 0; - - // The range of the random source must be a multiple of the modulus - // to give every possible output value an equal possibility - uint64_t nRange = (std::numeric_limits::max() / nMax) * nMax; - uint64_t nRand = 0; - do { - GetRandBytes((unsigned char*)&nRand, sizeof(nRand)); - } while (nRand >= nRange); - return (nRand % nMax); -} - -int GetRandInt(int nMax) -{ - return GetRand(nMax); -} - -uint256 GetRandHash() -{ - uint256 hash; - GetRandBytes((unsigned char*)&hash, sizeof(hash)); - return hash; -} - -uint32_t insecure_rand_Rz = 11; -uint32_t insecure_rand_Rw = 11; -void seed_insecure_rand(bool fDeterministic) -{ - // The seed values have some unlikely fixed points which we avoid. - if (fDeterministic) { - insecure_rand_Rz = insecure_rand_Rw = 11; - } else { - uint32_t tmp; - do { - GetRandBytes((unsigned char*)&tmp, 4); - } while (tmp == 0 || tmp == 0x9068ffffU); - insecure_rand_Rz = tmp; - do { - GetRandBytes((unsigned char*)&tmp, 4); - } while (tmp == 0 || tmp == 0x464fffffU); - insecure_rand_Rw = tmp; - } -} - -int GenIdentity(int n) -{ - return n-1; -} diff --git a/src/Native/libbeamhash/random.h b/src/Native/libbeamhash/random.h deleted file mode 100644 index 8cec678ef9..0000000000 --- a/src/Native/libbeamhash/random.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_RANDOM_H -#define BITCOIN_RANDOM_H - -#include "uint256.h" - -#include -#include - -/** - * Functions to gather random data via the libsodium CSPRNG - */ -void GetRandBytes(unsigned char* buf, size_t num); -uint64_t GetRand(uint64_t nMax); -int GetRandInt(int nMax); -uint256 GetRandHash(); - -/** - * Identity function for MappedShuffle, so that elements retain their original order. - */ - int GenIdentity(int n); - -/** - * Rearranges the elements in the range [first,first+len) randomly, assuming - * that gen is a uniform random number generator. Follows the same algorithm as - * std::shuffle in C++11 (a Durstenfeld shuffle). - * - * The elements in the range [mapFirst,mapFirst+len) are rearranged according to - * the same permutation, enabling the permutation to be tracked by the caller. - * - * gen takes an integer n and produces a uniform random output in [0,n). - */ -template -void MappedShuffle(RandomAccessIterator first, - MapRandomAccessIterator mapFirst, - size_t len, - std::function gen) -{ - for (size_t i = len-1; i > 0; --i) { - auto r = gen(i+1); - assert(r >= 0); - assert(r <= i); - std::swap(first[i], first[r]); - std::swap(mapFirst[i], mapFirst[r]); - } -} - -/** - * Seed insecure_rand using the random pool. - * @param Deterministic Use a deterministic seed - */ -void seed_insecure_rand(bool fDeterministic = false); - -/** - * MWC RNG of George Marsaglia - * This is intended to be fast. It has a period of 2^59.3, though the - * least significant 16 bits only have a period of about 2^30.1. - * - * @return random value - */ -extern uint32_t insecure_rand_Rz; -extern uint32_t insecure_rand_Rw; -static inline uint32_t insecure_rand(void) -{ - insecure_rand_Rz = 36969 * (insecure_rand_Rz & 65535) + (insecure_rand_Rz >> 16); - insecure_rand_Rw = 18000 * (insecure_rand_Rw & 65535) + (insecure_rand_Rw >> 16); - return (insecure_rand_Rw << 16) + insecure_rand_Rz; -} - -#endif // BITCOIN_RANDOM_H diff --git a/src/Native/libbeamhash/serialize.h b/src/Native/libbeamhash/serialize.h deleted file mode 100644 index 1402035f1d..0000000000 --- a/src/Native/libbeamhash/serialize.h +++ /dev/null @@ -1,997 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_SERIALIZE_H -#define BITCOIN_SERIALIZE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "crypto/common.h" - -class CScript; - -static const unsigned int MAX_SIZE = 0x02000000; - -/** - * Used to bypass the rule against non-const reference to temporary - * where it makes sense with wrappers such as CFlatData or CTxDB - */ -template -inline T& REF(const T& val) -{ - return const_cast(val); -} - -/** - * Used to acquire a non-const pointer "this" to generate bodies - * of const serialization operations from a template - */ -template -inline T* NCONST_PTR(const T* val) -{ - return const_cast(val); -} - -/** - * Get begin pointer of vector (non-const version). - * @note These functions avoid the undefined case of indexing into an empty - * vector, as well as that of indexing after the end of the vector. - */ -template -inline T* begin_ptr(std::vector& v) -{ - return v.empty() ? NULL : &v[0]; -} -/** Get begin pointer of vector (const version) */ -template -inline const T* begin_ptr(const std::vector& v) -{ - return v.empty() ? NULL : &v[0]; -} -/** Get end pointer of vector (non-const version) */ -template -inline T* end_ptr(std::vector& v) -{ - return v.empty() ? NULL : (&v[0] + v.size()); -} -/** Get end pointer of vector (const version) */ -template -inline const T* end_ptr(const std::vector& v) -{ - return v.empty() ? NULL : (&v[0] + v.size()); -} - -/* - * Lowest-level serialization and conversion. - * @note Sizes of these types are verified in the tests - */ -template inline void ser_writedata8(Stream &s, uint8_t obj) -{ - s.write((char*)&obj, 1); -} -template inline void ser_writedata16(Stream &s, uint16_t obj) -{ - obj = htole16(obj); - s.write((char*)&obj, 2); -} -template inline void ser_writedata32(Stream &s, uint32_t obj) -{ - obj = htole32(obj); - s.write((char*)&obj, 4); -} -template inline void ser_writedata64(Stream &s, uint64_t obj) -{ - obj = htole64(obj); - s.write((char*)&obj, 8); -} -template inline uint8_t ser_readdata8(Stream &s) -{ - uint8_t obj; - s.read((char*)&obj, 1); - return obj; -} -template inline uint16_t ser_readdata16(Stream &s) -{ - uint16_t obj; - s.read((char*)&obj, 2); - return le16toh(obj); -} -template inline uint32_t ser_readdata32(Stream &s) -{ - uint32_t obj; - s.read((char*)&obj, 4); - return le32toh(obj); -} -template inline uint64_t ser_readdata64(Stream &s) -{ - uint64_t obj; - s.read((char*)&obj, 8); - return le64toh(obj); -} -inline uint64_t ser_double_to_uint64(double x) -{ - union { double x; uint64_t y; } tmp; - tmp.x = x; - return tmp.y; -} -inline uint32_t ser_float_to_uint32(float x) -{ - union { float x; uint32_t y; } tmp; - tmp.x = x; - return tmp.y; -} -inline double ser_uint64_to_double(uint64_t y) -{ - union { double x; uint64_t y; } tmp; - tmp.y = y; - return tmp.x; -} -inline float ser_uint32_to_float(uint32_t y) -{ - union { float x; uint32_t y; } tmp; - tmp.y = y; - return tmp.x; -} - - -///////////////////////////////////////////////////////////////// -// -// Templates for serializing to anything that looks like a stream, -// i.e. anything that supports .read(char*, size_t) and .write(char*, size_t) -// - -enum -{ - // primary actions - SER_NETWORK = (1 << 0), - SER_DISK = (1 << 1), - SER_GETHASH = (1 << 2), -}; - -#define READWRITE(obj) (::SerReadWrite(s, (obj), nType, nVersion, ser_action)) - -/** - * Implement three methods for serializable objects. These are actually wrappers over - * "SerializationOp" template, which implements the body of each class' serialization - * code. Adding "ADD_SERIALIZE_METHODS" in the body of the class causes these wrappers to be - * added as members. - */ -#define ADD_SERIALIZE_METHODS \ - size_t GetSerializeSize(int nType, int nVersion) const { \ - CSizeComputer s(nType, nVersion); \ - NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), nType, nVersion);\ - return s.size(); \ - } \ - template \ - void Serialize(Stream& s, int nType, int nVersion) const { \ - NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), nType, nVersion);\ - } \ - template \ - void Unserialize(Stream& s, int nType, int nVersion) { \ - SerializationOp(s, CSerActionUnserialize(), nType, nVersion); \ - } - -/* - * Basic Types - */ -inline unsigned int GetSerializeSize(char a, int, int=0) { return 1; } -inline unsigned int GetSerializeSize(int8_t a, int, int=0) { return 1; } -inline unsigned int GetSerializeSize(uint8_t a, int, int=0) { return 1; } -inline unsigned int GetSerializeSize(int16_t a, int, int=0) { return 2; } -inline unsigned int GetSerializeSize(uint16_t a, int, int=0) { return 2; } -inline unsigned int GetSerializeSize(int32_t a, int, int=0) { return 4; } -inline unsigned int GetSerializeSize(uint32_t a, int, int=0) { return 4; } -inline unsigned int GetSerializeSize(int64_t a, int, int=0) { return 8; } -inline unsigned int GetSerializeSize(uint64_t a, int, int=0) { return 8; } -inline unsigned int GetSerializeSize(float a, int, int=0) { return 4; } -inline unsigned int GetSerializeSize(double a, int, int=0) { return 8; } - -template inline void Serialize(Stream& s, char a, int, int=0) { ser_writedata8(s, a); } // TODO Get rid of bare char -template inline void Serialize(Stream& s, int8_t a, int, int=0) { ser_writedata8(s, a); } -template inline void Serialize(Stream& s, uint8_t a, int, int=0) { ser_writedata8(s, a); } -template inline void Serialize(Stream& s, int16_t a, int, int=0) { ser_writedata16(s, a); } -template inline void Serialize(Stream& s, uint16_t a, int, int=0) { ser_writedata16(s, a); } -template inline void Serialize(Stream& s, int32_t a, int, int=0) { ser_writedata32(s, a); } -template inline void Serialize(Stream& s, uint32_t a, int, int=0) { ser_writedata32(s, a); } -template inline void Serialize(Stream& s, int64_t a, int, int=0) { ser_writedata64(s, a); } -template inline void Serialize(Stream& s, uint64_t a, int, int=0) { ser_writedata64(s, a); } -template inline void Serialize(Stream& s, float a, int, int=0) { ser_writedata32(s, ser_float_to_uint32(a)); } -template inline void Serialize(Stream& s, double a, int, int=0) { ser_writedata64(s, ser_double_to_uint64(a)); } - -template inline void Unserialize(Stream& s, char& a, int, int=0) { a = ser_readdata8(s); } // TODO Get rid of bare char -template inline void Unserialize(Stream& s, int8_t& a, int, int=0) { a = ser_readdata8(s); } -template inline void Unserialize(Stream& s, uint8_t& a, int, int=0) { a = ser_readdata8(s); } -template inline void Unserialize(Stream& s, int16_t& a, int, int=0) { a = ser_readdata16(s); } -template inline void Unserialize(Stream& s, uint16_t& a, int, int=0) { a = ser_readdata16(s); } -template inline void Unserialize(Stream& s, int32_t& a, int, int=0) { a = ser_readdata32(s); } -template inline void Unserialize(Stream& s, uint32_t& a, int, int=0) { a = ser_readdata32(s); } -template inline void Unserialize(Stream& s, int64_t& a, int, int=0) { a = ser_readdata64(s); } -template inline void Unserialize(Stream& s, uint64_t& a, int, int=0) { a = ser_readdata64(s); } -template inline void Unserialize(Stream& s, float& a, int, int=0) { a = ser_uint32_to_float(ser_readdata32(s)); } -template inline void Unserialize(Stream& s, double& a, int, int=0) { a = ser_uint64_to_double(ser_readdata64(s)); } - -inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); } -template inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; ser_writedata8(s, f); } -template inline void Unserialize(Stream& s, bool& a, int, int=0) { char f=ser_readdata8(s); a=f; } - - - - - - -/** - * Compact Size - * size < 253 -- 1 byte - * size <= 0xFFFF -- 3 bytes (253 + 2 bytes) - * size <= 0xFFFFFFFF -- 5 bytes (254 + 4 bytes) - * size > 0xFFFFFFFF -- 9 bytes (255 + 8 bytes) - */ -inline unsigned int GetSizeOfCompactSize(uint64_t nSize) -{ - if (nSize < 253) return 1; - else if (nSize <= 0xFFFFu) return 3; - else if (nSize <= 0xFFFFFFFFu) return 5; - else return 9; -} - -template -void WriteCompactSize(Stream& os, uint64_t nSize) -{ - if (nSize < 253) - { - ser_writedata8(os, nSize); - } - else if (nSize <= 0xFFFFu) - { - ser_writedata8(os, 253); - ser_writedata16(os, nSize); - } - else if (nSize <= 0xFFFFFFFFu) - { - ser_writedata8(os, 254); - ser_writedata32(os, nSize); - } - else - { - ser_writedata8(os, 255); - ser_writedata64(os, nSize); - } -} - -template -uint64_t ReadCompactSize(Stream& is) -{ - uint8_t chSize = ser_readdata8(is); - uint64_t nSizeRet = 0; - if (chSize < 253) - { - nSizeRet = chSize; - } - else if (chSize == 253) - { - nSizeRet = ser_readdata16(is); - if (nSizeRet < 253) - throw std::ios_base::failure("non-canonical ReadCompactSize()"); - } - else if (chSize == 254) - { - nSizeRet = ser_readdata32(is); - if (nSizeRet < 0x10000u) - throw std::ios_base::failure("non-canonical ReadCompactSize()"); - } - else - { - nSizeRet = ser_readdata64(is); - if (nSizeRet < 0x100000000ULL) - throw std::ios_base::failure("non-canonical ReadCompactSize()"); - } - if (nSizeRet > (uint64_t)MAX_SIZE) - throw std::ios_base::failure("ReadCompactSize(): size too large"); - return nSizeRet; -} - -/** - * Variable-length integers: bytes are a MSB base-128 encoding of the number. - * The high bit in each byte signifies whether another digit follows. To make - * sure the encoding is one-to-one, one is subtracted from all but the last digit. - * Thus, the byte sequence a[] with length len, where all but the last byte - * has bit 128 set, encodes the number: - * - * (a[len-1] & 0x7F) + sum(i=1..len-1, 128^i*((a[len-i-1] & 0x7F)+1)) - * - * Properties: - * * Very small (0-127: 1 byte, 128-16511: 2 bytes, 16512-2113663: 3 bytes) - * * Every integer has exactly one encoding - * * Encoding does not depend on size of original integer type - * * No redundancy: every (infinite) byte sequence corresponds to a list - * of encoded integers. - * - * 0: [0x00] 256: [0x81 0x00] - * 1: [0x01] 16383: [0xFE 0x7F] - * 127: [0x7F] 16384: [0xFF 0x00] - * 128: [0x80 0x00] 16511: [0x80 0xFF 0x7F] - * 255: [0x80 0x7F] 65535: [0x82 0xFD 0x7F] - * 2^32: [0x8E 0xFE 0xFE 0xFF 0x00] - */ - -template -inline unsigned int GetSizeOfVarInt(I n) -{ - int nRet = 0; - while(true) { - nRet++; - if (n <= 0x7F) - break; - n = (n >> 7) - 1; - } - return nRet; -} - -template -void WriteVarInt(Stream& os, I n) -{ - unsigned char tmp[(sizeof(n)*8+6)/7]; - int len=0; - while(true) { - tmp[len] = (n & 0x7F) | (len ? 0x80 : 0x00); - if (n <= 0x7F) - break; - n = (n >> 7) - 1; - len++; - } - do { - ser_writedata8(os, tmp[len]); - } while(len--); -} - -template -I ReadVarInt(Stream& is) -{ - I n = 0; - while(true) { - unsigned char chData = ser_readdata8(is); - n = (n << 7) | (chData & 0x7F); - if (chData & 0x80) - n++; - else - return n; - } -} - -#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) -#define VARINT(obj) REF(WrapVarInt(REF(obj))) -#define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj))) - -/** - * Wrapper for serializing arrays and POD. - */ -class CFlatData -{ -protected: - char* pbegin; - char* pend; -public: - CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { } - template - explicit CFlatData(std::vector &v) - { - pbegin = (char*)begin_ptr(v); - pend = (char*)end_ptr(v); - } - char* begin() { return pbegin; } - const char* begin() const { return pbegin; } - char* end() { return pend; } - const char* end() const { return pend; } - - unsigned int GetSerializeSize(int, int=0) const - { - return pend - pbegin; - } - - template - void Serialize(Stream& s, int, int=0) const - { - s.write(pbegin, pend - pbegin); - } - - template - void Unserialize(Stream& s, int, int=0) - { - s.read(pbegin, pend - pbegin); - } -}; - -template -class CVarInt -{ -protected: - I &n; -public: - CVarInt(I& nIn) : n(nIn) { } - - unsigned int GetSerializeSize(int, int) const { - return GetSizeOfVarInt(n); - } - - template - void Serialize(Stream &s, int, int) const { - WriteVarInt(s, n); - } - - template - void Unserialize(Stream& s, int, int) { - n = ReadVarInt(s); - } -}; - -template -class LimitedString -{ -protected: - std::string& string; -public: - LimitedString(std::string& string) : string(string) {} - - template - void Unserialize(Stream& s, int, int=0) - { - size_t size = ReadCompactSize(s); - if (size > Limit) { - throw std::ios_base::failure("String length limit exceeded"); - } - string.resize(size); - if (size != 0) - s.read((char*)&string[0], size); - } - - template - void Serialize(Stream& s, int, int=0) const - { - WriteCompactSize(s, string.size()); - if (!string.empty()) - s.write((char*)&string[0], string.size()); - } - - unsigned int GetSerializeSize(int, int=0) const - { - return GetSizeOfCompactSize(string.size()) + string.size(); - } -}; - -template -CVarInt WrapVarInt(I& n) { return CVarInt(n); } - -/** - * Forward declarations - */ - -/** - * string - */ -template unsigned int GetSerializeSize(const std::basic_string& str, int, int=0); -template void Serialize(Stream& os, const std::basic_string& str, int, int=0); -template void Unserialize(Stream& is, std::basic_string& str, int, int=0); - -/** - * vector - * vectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. - */ -template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const unsigned char&); -template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const V&); -template inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion); -template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const unsigned char&); -template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const V&); -template inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion); -template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const unsigned char&); -template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const V&); -template inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion); - -/** - * others derived from vector - */ -extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion); -template void Serialize(Stream& os, const CScript& v, int nType, int nVersion); -template void Unserialize(Stream& is, CScript& v, int nType, int nVersion); - -/** - * optional - */ -template unsigned int GetSerializeSize(const boost::optional &item, int nType, int nVersion); -template void Serialize(Stream& os, const boost::optional& item, int nType, int nVersion); -template void Unserialize(Stream& is, boost::optional& item, int nType, int nVersion); - -/** - * array - */ -template unsigned int GetSerializeSize(const boost::array &item, int nType, int nVersion); -template void Serialize(Stream& os, const boost::array& item, int nType, int nVersion); -template void Unserialize(Stream& is, boost::array& item, int nType, int nVersion); - -/** - * pair - */ -template unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion); -template void Serialize(Stream& os, const std::pair& item, int nType, int nVersion); -template void Unserialize(Stream& is, std::pair& item, int nType, int nVersion); - -/** - * map - */ -template unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion); -template void Serialize(Stream& os, const std::map& m, int nType, int nVersion); -template void Unserialize(Stream& is, std::map& m, int nType, int nVersion); - -/** - * set - */ -template unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion); -template void Serialize(Stream& os, const std::set& m, int nType, int nVersion); -template void Unserialize(Stream& is, std::set& m, int nType, int nVersion); - -/** - * list - */ -template unsigned int GetSerializeSize(const std::list& m, int nType, int nVersion); -template void Serialize(Stream& os, const std::list& m, int nType, int nVersion); -template void Unserialize(Stream& is, std::list& m, int nType, int nVersion); - - - - - -/** - * If none of the specialized versions above matched, default to calling member function. - * "int nType" is changed to "long nType" to keep from getting an ambiguous overload error. - * The compiler will only cast int to long if none of the other templates matched. - * Thanks to Boost serialization for this idea. - */ -template -inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion) -{ - return a.GetSerializeSize((int)nType, nVersion); -} - -template -inline void Serialize(Stream& os, const T& a, long nType, int nVersion) -{ - a.Serialize(os, (int)nType, nVersion); -} - -template -inline void Unserialize(Stream& is, T& a, long nType, int nVersion) -{ - a.Unserialize(is, (int)nType, nVersion); -} - - - - - -/** - * string - */ -template -unsigned int GetSerializeSize(const std::basic_string& str, int, int) -{ - return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]); -} - -template -void Serialize(Stream& os, const std::basic_string& str, int, int) -{ - WriteCompactSize(os, str.size()); - if (!str.empty()) - os.write((char*)&str[0], str.size() * sizeof(str[0])); -} - -template -void Unserialize(Stream& is, std::basic_string& str, int, int) -{ - unsigned int nSize = ReadCompactSize(is); - str.resize(nSize); - if (nSize != 0) - is.read((char*)&str[0], nSize * sizeof(str[0])); -} - - - -/** - * vector - */ -template -unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const unsigned char&) -{ - return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); -} - -template -unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const V&) -{ - unsigned int nSize = GetSizeOfCompactSize(v.size()); - for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) - nSize += GetSerializeSize((*vi), nType, nVersion); - return nSize; -} - -template -inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion) -{ - return GetSerializeSize_impl(v, nType, nVersion, T()); -} - - -template -void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const unsigned char&) -{ - WriteCompactSize(os, v.size()); - if (!v.empty()) - os.write((char*)&v[0], v.size() * sizeof(T)); -} - -template -void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const V&) -{ - WriteCompactSize(os, v.size()); - for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) - ::Serialize(os, (*vi), nType, nVersion); -} - -template -inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion) -{ - Serialize_impl(os, v, nType, nVersion, T()); -} - - -template -void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const unsigned char&) -{ - // Limit size per read so bogus size value won't cause out of memory - v.clear(); - unsigned int nSize = ReadCompactSize(is); - unsigned int i = 0; - while (i < nSize) - { - unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); - v.resize(i + blk); - is.read((char*)&v[i], blk * sizeof(T)); - i += blk; - } -} - -template -void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const V&) -{ - v.clear(); - unsigned int nSize = ReadCompactSize(is); - unsigned int i = 0; - unsigned int nMid = 0; - while (nMid < nSize) - { - nMid += 5000000 / sizeof(T); - if (nMid > nSize) - nMid = nSize; - v.resize(nMid); - for (; i < nMid; i++) - Unserialize(is, v[i], nType, nVersion); - } -} - -template -inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion) -{ - Unserialize_impl(is, v, nType, nVersion, T()); -} - - - -/** - * others derived from vector - */ -inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion) -{ - return GetSerializeSize((const std::vector&)v, nType, nVersion); -} - -template -void Serialize(Stream& os, const CScript& v, int nType, int nVersion) -{ - Serialize(os, (const std::vector&)v, nType, nVersion); -} - -template -void Unserialize(Stream& is, CScript& v, int nType, int nVersion) -{ - Unserialize(is, (std::vector&)v, nType, nVersion); -} - - - -/** - * optional - */ -template -unsigned int GetSerializeSize(const boost::optional &item, int nType, int nVersion) -{ - if (item) { - return 1 + GetSerializeSize(*item, nType, nVersion); - } else { - return 1; - } -} - -template -void Serialize(Stream& os, const boost::optional& item, int nType, int nVersion) -{ - // If the value is there, put 0x01 and then serialize the value. - // If it's not, put 0x00. - if (item) { - unsigned char discriminant = 0x01; - Serialize(os, discriminant, nType, nVersion); - Serialize(os, *item, nType, nVersion); - } else { - unsigned char discriminant = 0x00; - Serialize(os, discriminant, nType, nVersion); - } -} - -template -void Unserialize(Stream& is, boost::optional& item, int nType, int nVersion) -{ - unsigned char discriminant = 0x00; - Unserialize(is, discriminant, nType, nVersion); - - if (discriminant == 0x00) { - item = boost::none; - } else if (discriminant == 0x01) { - T object; - Unserialize(is, object, nType, nVersion); - item = object; - } else { - throw std::ios_base::failure("non-canonical optional discriminant"); - } -} - - - -/** - * array - */ -template -unsigned int GetSerializeSize(const boost::array &item, int nType, int nVersion) -{ - unsigned int size = 0; - for (size_t i = 0; i < N; i++) { - size += GetSerializeSize(item[0], nType, nVersion); - } - return size; -} - -template -void Serialize(Stream& os, const boost::array& item, int nType, int nVersion) -{ - for (size_t i = 0; i < N; i++) { - Serialize(os, item[i], nType, nVersion); - } -} - -template -void Unserialize(Stream& is, boost::array& item, int nType, int nVersion) -{ - for (size_t i = 0; i < N; i++) { - Unserialize(is, item[i], nType, nVersion); - } -} - - -/** - * pair - */ -template -unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion) -{ - return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion); -} - -template -void Serialize(Stream& os, const std::pair& item, int nType, int nVersion) -{ - Serialize(os, item.first, nType, nVersion); - Serialize(os, item.second, nType, nVersion); -} - -template -void Unserialize(Stream& is, std::pair& item, int nType, int nVersion) -{ - Unserialize(is, item.first, nType, nVersion); - Unserialize(is, item.second, nType, nVersion); -} - - - -/** - * map - */ -template -unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion) -{ - unsigned int nSize = GetSizeOfCompactSize(m.size()); - for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) - nSize += GetSerializeSize((*mi), nType, nVersion); - return nSize; -} - -template -void Serialize(Stream& os, const std::map& m, int nType, int nVersion) -{ - WriteCompactSize(os, m.size()); - for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) - Serialize(os, (*mi), nType, nVersion); -} - -template -void Unserialize(Stream& is, std::map& m, int nType, int nVersion) -{ - m.clear(); - unsigned int nSize = ReadCompactSize(is); - typename std::map::iterator mi = m.begin(); - for (unsigned int i = 0; i < nSize; i++) - { - std::pair item; - Unserialize(is, item, nType, nVersion); - mi = m.insert(mi, item); - } -} - - - -/** - * set - */ -template -unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion) -{ - unsigned int nSize = GetSizeOfCompactSize(m.size()); - for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) - nSize += GetSerializeSize((*it), nType, nVersion); - return nSize; -} - -template -void Serialize(Stream& os, const std::set& m, int nType, int nVersion) -{ - WriteCompactSize(os, m.size()); - for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) - Serialize(os, (*it), nType, nVersion); -} - -template -void Unserialize(Stream& is, std::set& m, int nType, int nVersion) -{ - m.clear(); - unsigned int nSize = ReadCompactSize(is); - typename std::set::iterator it = m.begin(); - for (unsigned int i = 0; i < nSize; i++) - { - K key; - Unserialize(is, key, nType, nVersion); - it = m.insert(it, key); - } -} - - - -/** - * list - */ -template -unsigned int GetSerializeSize(const std::list& l, int nType, int nVersion) -{ - unsigned int nSize = GetSizeOfCompactSize(l.size()); - for (typename std::list::const_iterator it = l.begin(); it != l.end(); ++it) - nSize += GetSerializeSize((*it), nType, nVersion); - return nSize; -} - -template -void Serialize(Stream& os, const std::list& l, int nType, int nVersion) -{ - WriteCompactSize(os, l.size()); - for (typename std::list::const_iterator it = l.begin(); it != l.end(); ++it) - Serialize(os, (*it), nType, nVersion); -} - -template -void Unserialize(Stream& is, std::list& l, int nType, int nVersion) -{ - l.clear(); - unsigned int nSize = ReadCompactSize(is); - typename std::list::iterator it = l.begin(); - for (unsigned int i = 0; i < nSize; i++) - { - T item; - Unserialize(is, item, nType, nVersion); - l.push_back(item); - } -} - - - -/** - * Support for ADD_SERIALIZE_METHODS and READWRITE macro - */ -struct CSerActionSerialize -{ - bool ForRead() const { return false; } -}; -struct CSerActionUnserialize -{ - bool ForRead() const { return true; } -}; - -template -inline void SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action) -{ - ::Serialize(s, obj, nType, nVersion); -} - -template -inline void SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action) -{ - ::Unserialize(s, obj, nType, nVersion); -} - - - - - - - - - -class CSizeComputer -{ -protected: - size_t nSize; - -public: - int nType; - int nVersion; - - CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {} - - CSizeComputer& write(const char *psz, size_t nSize) - { - this->nSize += nSize; - return *this; - } - - template - CSizeComputer& operator<<(const T& obj) - { - ::Serialize(*this, obj, nType, nVersion); - return (*this); - } - - size_t size() const { - return nSize; - } -}; - -#endif // BITCOIN_SERIALIZE_H diff --git a/src/Native/libbeamhash/sha256.h b/src/Native/libbeamhash/sha256.h new file mode 100644 index 0000000000..ae9302f1d1 --- /dev/null +++ b/src/Native/libbeamhash/sha256.h @@ -0,0 +1,34 @@ + +// Copyright (c) 2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CRYPTO_SHA256_H +#define BITCOIN_CRYPTO_SHA256_H + +#include +#include + +/** A hasher class for SHA-256. */ +class CSHA256 +{ +public: + static const size_t OUTPUT_SIZE = 32; + + CSHA256(); + CSHA256& Write(const unsigned char* data, size_t len); + void Finalize(unsigned char hash[OUTPUT_SIZE]); + void FinalizeNoPadding(unsigned char hash[OUTPUT_SIZE]) + { + FinalizeNoPadding(hash, true); + }; + CSHA256& Reset(); + +private: + uint32_t s[8]; + unsigned char buf[64]; + size_t bytes; + void FinalizeNoPadding(unsigned char hash[OUTPUT_SIZE], bool enforce_compression); +}; + +#endif // BITCOIN_CRYPTO_SHA256_H \ No newline at end of file diff --git a/src/Native/libbeamhash/support/cleanse.cpp b/src/Native/libbeamhash/support/cleanse.cpp deleted file mode 100644 index a2141b2449..0000000000 --- a/src/Native/libbeamhash/support/cleanse.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2015 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "cleanse.h" - -#include - -void memory_cleanse(void *ptr, size_t len) -{ - OPENSSL_cleanse(ptr, len); -} diff --git a/src/Native/libbeamhash/support/cleanse.h b/src/Native/libbeamhash/support/cleanse.h deleted file mode 100644 index 3e02aa8fd1..0000000000 --- a/src/Native/libbeamhash/support/cleanse.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2015 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_SUPPORT_CLEANSE_H -#define BITCOIN_SUPPORT_CLEANSE_H - -#include - -void memory_cleanse(void *ptr, size_t len); - -#endif // BITCOIN_SUPPORT_CLEANSE_H diff --git a/src/Native/libbeamhash/tinyformat.h b/src/Native/libbeamhash/tinyformat.h deleted file mode 100644 index 57f7672504..0000000000 --- a/src/Native/libbeamhash/tinyformat.h +++ /dev/null @@ -1,1049 +0,0 @@ -// tinyformat.h -// Copyright (C) 2011, Chris Foster [chris42f (at) gmail (d0t) com] -// -// Boost Software License - Version 1.0 -// -// Permission is hereby granted, free of charge, to any person or organization -// obtaining a copy of the software and accompanying documentation covered by -// this license (the "Software") to use, reproduce, display, distribute, -// execute, and transmit the Software, and to prepare derivative works of the -// Software, and to permit third-parties to whom the Software is furnished to -// do so, all subject to the following: -// -// The copyright notices in the Software and this entire statement, including -// the above license grant, this restriction and the following disclaimer, -// must be included in all copies of the Software, in whole or in part, and -// all derivative works of the Software, unless such copies or derivative -// works are solely in the form of machine-executable object code generated by -// a source language processor. -// -// 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT -// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -//------------------------------------------------------------------------------ -// Tinyformat: A minimal type safe printf replacement -// -// tinyformat.h is a type safe printf replacement library in a single C++ -// header file. Design goals include: -// -// * Type safety and extensibility for user defined types. -// * C99 printf() compatibility, to the extent possible using std::ostream -// * Simplicity and minimalism. A single header file to include and distribute -// with your projects. -// * Augment rather than replace the standard stream formatting mechanism -// * C++98 support, with optional C++11 niceties -// -// -// Main interface example usage -// ---------------------------- -// -// To print a date to std::cout: -// -// std::string weekday = "Wednesday"; -// const char* month = "July"; -// size_t day = 27; -// long hour = 14; -// int min = 44; -// -// tfm::printf("%s, %s %d, %.2d:%.2d\n", weekday, month, day, hour, min); -// -// The strange types here emphasize the type safety of the interface; it is -// possible to print a std::string using the "%s" conversion, and a -// size_t using the "%d" conversion. A similar result could be achieved -// using either of the tfm::format() functions. One prints on a user provided -// stream: -// -// tfm::format(std::cerr, "%s, %s %d, %.2d:%.2d\n", -// weekday, month, day, hour, min); -// -// The other returns a std::string: -// -// std::string date = tfm::format("%s, %s %d, %.2d:%.2d\n", -// weekday, month, day, hour, min); -// std::cout << date; -// -// These are the three primary interface functions. There is also a -// convenience function printfln() which appends a newline to the usual result -// of printf() for super simple logging. -// -// -// User defined format functions -// ----------------------------- -// -// Simulating variadic templates in C++98 is pretty painful since it requires -// writing out the same function for each desired number of arguments. To make -// this bearable tinyformat comes with a set of macros which are used -// internally to generate the API, but which may also be used in user code. -// -// The three macros TINYFORMAT_ARGTYPES(n), TINYFORMAT_VARARGS(n) and -// TINYFORMAT_PASSARGS(n) will generate a list of n argument types, -// type/name pairs and argument names respectively when called with an integer -// n between 1 and 16. We can use these to define a macro which generates the -// desired user defined function with n arguments. To generate all 16 user -// defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM. For an -// example, see the implementation of printf() at the end of the source file. -// -// Sometimes it's useful to be able to pass a list of format arguments through -// to a non-template function. The FormatList class is provided as a way to do -// this by storing the argument list in a type-opaque way. Continuing the -// example from above, we construct a FormatList using makeFormatList(): -// -// FormatListRef formatList = tfm::makeFormatList(weekday, month, day, hour, min); -// -// The format list can now be passed into any non-template function and used -// via a call to the vformat() function: -// -// tfm::vformat(std::cout, "%s, %s %d, %.2d:%.2d\n", formatList); -// -// -// Additional API information -// -------------------------- -// -// Error handling: Define TINYFORMAT_ERROR to customize the error handling for -// format strings which are unsupported or have the wrong number of format -// specifiers (calls assert() by default). -// -// User defined types: Uses operator<< for user defined types by default. -// Overload formatValue() for more control. - - -#ifndef TINYFORMAT_H_INCLUDED -#define TINYFORMAT_H_INCLUDED - -namespace tinyformat {} -//------------------------------------------------------------------------------ -// Config section. Customize to your liking! - -// Namespace alias to encourage brevity -namespace tfm = tinyformat; - -// Error handling; calls assert() by default. -#define TINYFORMAT_ERROR(reasonString) throw std::runtime_error(reasonString) - -// Define for C++11 variadic templates which make the code shorter & more -// general. If you don't define this, C++11 support is autodetected below. -// #define TINYFORMAT_USE_VARIADIC_TEMPLATES - - -//------------------------------------------------------------------------------ -// Implementation details. -#include -#include -#include -#include -#include - -#ifndef TINYFORMAT_ERROR -# define TINYFORMAT_ERROR(reason) assert(0 && reason) -#endif - -#if !defined(TINYFORMAT_USE_VARIADIC_TEMPLATES) && !defined(TINYFORMAT_NO_VARIADIC_TEMPLATES) -# ifdef __GXX_EXPERIMENTAL_CXX0X__ -# define TINYFORMAT_USE_VARIADIC_TEMPLATES -# endif -#endif - -#if defined(__GLIBCXX__) && __GLIBCXX__ < 20080201 -// std::showpos is broken on old libstdc++ as provided with OSX. See -// http://gcc.gnu.org/ml/libstdc++/2007-11/msg00075.html -# define TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND -#endif - -#ifdef __APPLE__ -// Workaround macOS linker warning: Xcode uses different default symbol -// visibilities for static libs vs executables (see issue #25) -# define TINYFORMAT_HIDDEN __attribute__((visibility("hidden"))) -#else -# define TINYFORMAT_HIDDEN -#endif - -namespace tinyformat { - -//------------------------------------------------------------------------------ -namespace detail { - -// Test whether type T1 is convertible to type T2 -template -struct is_convertible -{ - private: - // two types of different size - struct fail { char dummy[2]; }; - struct succeed { char dummy; }; - // Try to convert a T1 to a T2 by plugging into tryConvert - static fail tryConvert(...); - static succeed tryConvert(const T2&); - static const T1& makeT1(); - public: -# ifdef _MSC_VER - // Disable spurious loss of precision warnings in tryConvert(makeT1()) -# pragma warning(push) -# pragma warning(disable:4244) -# pragma warning(disable:4267) -# endif - // Standard trick: the (...) version of tryConvert will be chosen from - // the overload set only if the version taking a T2 doesn't match. - // Then we compare the sizes of the return types to check which - // function matched. Very neat, in a disgusting kind of way :) - static const bool value = - sizeof(tryConvert(makeT1())) == sizeof(succeed); -# ifdef _MSC_VER -# pragma warning(pop) -# endif -}; - - -// Detect when a type is not a wchar_t string -template struct is_wchar { typedef int tinyformat_wchar_is_not_supported; }; -template<> struct is_wchar {}; -template<> struct is_wchar {}; -template struct is_wchar {}; -template struct is_wchar {}; - - -// Format the value by casting to type fmtT. This default implementation -// should never be called. -template::value> -struct formatValueAsType -{ - static void invoke(std::ostream& /*out*/, const T& /*value*/) { assert(0); } -}; -// Specialized version for types that can actually be converted to fmtT, as -// indicated by the "convertible" template parameter. -template -struct formatValueAsType -{ - static void invoke(std::ostream& out, const T& value) - { out << static_cast(value); } -}; - -#ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND -template::value> -struct formatZeroIntegerWorkaround -{ - static bool invoke(std::ostream& /**/, const T& /**/) { return false; } -}; -template -struct formatZeroIntegerWorkaround -{ - static bool invoke(std::ostream& out, const T& value) - { - if (static_cast(value) == 0 && out.flags() & std::ios::showpos) - { - out << "+0"; - return true; - } - return false; - } -}; -#endif // TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND - -// Convert an arbitrary type to integer. The version with convertible=false -// throws an error. -template::value> -struct convertToInt -{ - static int invoke(const T& /*value*/) - { - TINYFORMAT_ERROR("tinyformat: Cannot convert from argument type to " - "integer for use as variable width or precision"); - return 0; - } -}; -// Specialization for convertToInt when conversion is possible -template -struct convertToInt -{ - static int invoke(const T& value) { return static_cast(value); } -}; - -// Format at most ntrunc characters to the given stream. -template -inline void formatTruncated(std::ostream& out, const T& value, int ntrunc) -{ - std::ostringstream tmp; - tmp << value; - std::string result = tmp.str(); - out.write(result.c_str(), (std::min)(ntrunc, static_cast(result.size()))); -} -#define TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(type) \ -inline void formatTruncated(std::ostream& out, type* value, int ntrunc) \ -{ \ - std::streamsize len = 0; \ - while(len < ntrunc && value[len] != 0) \ - ++len; \ - out.write(value, len); \ -} -// Overload for const char* and char*. Could overload for signed & unsigned -// char too, but these are technically unneeded for printf compatibility. -TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(const char) -TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(char) -#undef TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR - -} // namespace detail - - -//------------------------------------------------------------------------------ -// Variable formatting functions. May be overridden for user-defined types if -// desired. - - -/// Format a value into a stream, delegating to operator<< by default. -/// -/// Users may override this for their own types. When this function is called, -/// the stream flags will have been modified according to the format string. -/// The format specification is provided in the range [fmtBegin, fmtEnd). For -/// truncating conversions, ntrunc is set to the desired maximum number of -/// characters, for example "%.7s" calls formatValue with ntrunc = 7. -/// -/// By default, formatValue() uses the usual stream insertion operator -/// operator<< to format the type T, with special cases for the %c and %p -/// conversions. -template -inline void formatValue(std::ostream& out, const char* /*fmtBegin*/, - const char* fmtEnd, int ntrunc, const T& value) -{ -#ifndef TINYFORMAT_ALLOW_WCHAR_STRINGS - // Since we don't support printing of wchar_t using "%ls", make it fail at - // compile time in preference to printing as a void* at runtime. - typedef typename detail::is_wchar::tinyformat_wchar_is_not_supported DummyType; - (void) DummyType(); // avoid unused type warning with gcc-4.8 -#endif - // The mess here is to support the %c and %p conversions: if these - // conversions are active we try to convert the type to a char or const - // void* respectively and format that instead of the value itself. For the - // %p conversion it's important to avoid dereferencing the pointer, which - // could otherwise lead to a crash when printing a dangling (const char*). - const bool canConvertToChar = detail::is_convertible::value; - const bool canConvertToVoidPtr = detail::is_convertible::value; - if(canConvertToChar && *(fmtEnd-1) == 'c') - detail::formatValueAsType::invoke(out, value); - else if(canConvertToVoidPtr && *(fmtEnd-1) == 'p') - detail::formatValueAsType::invoke(out, value); -#ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND - else if(detail::formatZeroIntegerWorkaround::invoke(out, value)) /**/; -#endif - else if(ntrunc >= 0) - { - // Take care not to overread C strings in truncating conversions like - // "%.4s" where at most 4 characters may be read. - detail::formatTruncated(out, value, ntrunc); - } - else - out << value; -} - - -// Overloaded version for char types to support printing as an integer -#define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType) \ -inline void formatValue(std::ostream& out, const char* /*fmtBegin*/, \ - const char* fmtEnd, int /**/, charType value) \ -{ \ - switch(*(fmtEnd-1)) \ - { \ - case 'u': case 'd': case 'i': case 'o': case 'X': case 'x': \ - out << static_cast(value); break; \ - default: \ - out << value; break; \ - } \ -} -// per 3.9.1: char, signed char and unsigned char are all distinct types -TINYFORMAT_DEFINE_FORMATVALUE_CHAR(char) -TINYFORMAT_DEFINE_FORMATVALUE_CHAR(signed char) -TINYFORMAT_DEFINE_FORMATVALUE_CHAR(unsigned char) -#undef TINYFORMAT_DEFINE_FORMATVALUE_CHAR - - -//------------------------------------------------------------------------------ -// Tools for emulating variadic templates in C++98. The basic idea here is -// stolen from the boost preprocessor metaprogramming library and cut down to -// be just general enough for what we need. - -#define TINYFORMAT_ARGTYPES(n) TINYFORMAT_ARGTYPES_ ## n -#define TINYFORMAT_VARARGS(n) TINYFORMAT_VARARGS_ ## n -#define TINYFORMAT_PASSARGS(n) TINYFORMAT_PASSARGS_ ## n -#define TINYFORMAT_PASSARGS_TAIL(n) TINYFORMAT_PASSARGS_TAIL_ ## n - -// To keep it as transparent as possible, the macros below have been generated -// using python via the excellent cog.py code generation script. This avoids -// the need for a bunch of complex (but more general) preprocessor tricks as -// used in boost.preprocessor. -// -// To rerun the code generation in place, use `cog.py -r tinyformat.h` -// (see http://nedbatchelder.com/code/cog). Alternatively you can just create -// extra versions by hand. - -/*[[[cog -maxParams = 16 - -def makeCommaSepLists(lineTemplate, elemTemplate, startInd=1): - for j in range(startInd,maxParams+1): - list = ', '.join([elemTemplate % {'i':i} for i in range(startInd,j+1)]) - cog.outl(lineTemplate % {'j':j, 'list':list}) - -makeCommaSepLists('#define TINYFORMAT_ARGTYPES_%(j)d %(list)s', - 'class T%(i)d') - -cog.outl() -makeCommaSepLists('#define TINYFORMAT_VARARGS_%(j)d %(list)s', - 'const T%(i)d& v%(i)d') - -cog.outl() -makeCommaSepLists('#define TINYFORMAT_PASSARGS_%(j)d %(list)s', 'v%(i)d') - -cog.outl() -cog.outl('#define TINYFORMAT_PASSARGS_TAIL_1') -makeCommaSepLists('#define TINYFORMAT_PASSARGS_TAIL_%(j)d , %(list)s', - 'v%(i)d', startInd = 2) - -cog.outl() -cog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n ' + - ' '.join(['m(%d)' % (j,) for j in range(1,maxParams+1)])) -]]]*/ -#define TINYFORMAT_ARGTYPES_1 class T1 -#define TINYFORMAT_ARGTYPES_2 class T1, class T2 -#define TINYFORMAT_ARGTYPES_3 class T1, class T2, class T3 -#define TINYFORMAT_ARGTYPES_4 class T1, class T2, class T3, class T4 -#define TINYFORMAT_ARGTYPES_5 class T1, class T2, class T3, class T4, class T5 -#define TINYFORMAT_ARGTYPES_6 class T1, class T2, class T3, class T4, class T5, class T6 -#define TINYFORMAT_ARGTYPES_7 class T1, class T2, class T3, class T4, class T5, class T6, class T7 -#define TINYFORMAT_ARGTYPES_8 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8 -#define TINYFORMAT_ARGTYPES_9 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9 -#define TINYFORMAT_ARGTYPES_10 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10 -#define TINYFORMAT_ARGTYPES_11 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11 -#define TINYFORMAT_ARGTYPES_12 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12 -#define TINYFORMAT_ARGTYPES_13 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13 -#define TINYFORMAT_ARGTYPES_14 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14 -#define TINYFORMAT_ARGTYPES_15 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 -#define TINYFORMAT_ARGTYPES_16 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16 - -#define TINYFORMAT_VARARGS_1 const T1& v1 -#define TINYFORMAT_VARARGS_2 const T1& v1, const T2& v2 -#define TINYFORMAT_VARARGS_3 const T1& v1, const T2& v2, const T3& v3 -#define TINYFORMAT_VARARGS_4 const T1& v1, const T2& v2, const T3& v3, const T4& v4 -#define TINYFORMAT_VARARGS_5 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5 -#define TINYFORMAT_VARARGS_6 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6 -#define TINYFORMAT_VARARGS_7 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7 -#define TINYFORMAT_VARARGS_8 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8 -#define TINYFORMAT_VARARGS_9 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9 -#define TINYFORMAT_VARARGS_10 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10 -#define TINYFORMAT_VARARGS_11 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11 -#define TINYFORMAT_VARARGS_12 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12 -#define TINYFORMAT_VARARGS_13 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13 -#define TINYFORMAT_VARARGS_14 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14 -#define TINYFORMAT_VARARGS_15 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14, const T15& v15 -#define TINYFORMAT_VARARGS_16 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14, const T15& v15, const T16& v16 - -#define TINYFORMAT_PASSARGS_1 v1 -#define TINYFORMAT_PASSARGS_2 v1, v2 -#define TINYFORMAT_PASSARGS_3 v1, v2, v3 -#define TINYFORMAT_PASSARGS_4 v1, v2, v3, v4 -#define TINYFORMAT_PASSARGS_5 v1, v2, v3, v4, v5 -#define TINYFORMAT_PASSARGS_6 v1, v2, v3, v4, v5, v6 -#define TINYFORMAT_PASSARGS_7 v1, v2, v3, v4, v5, v6, v7 -#define TINYFORMAT_PASSARGS_8 v1, v2, v3, v4, v5, v6, v7, v8 -#define TINYFORMAT_PASSARGS_9 v1, v2, v3, v4, v5, v6, v7, v8, v9 -#define TINYFORMAT_PASSARGS_10 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 -#define TINYFORMAT_PASSARGS_11 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 -#define TINYFORMAT_PASSARGS_12 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 -#define TINYFORMAT_PASSARGS_13 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 -#define TINYFORMAT_PASSARGS_14 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 -#define TINYFORMAT_PASSARGS_15 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 -#define TINYFORMAT_PASSARGS_16 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 - -#define TINYFORMAT_PASSARGS_TAIL_1 -#define TINYFORMAT_PASSARGS_TAIL_2 , v2 -#define TINYFORMAT_PASSARGS_TAIL_3 , v2, v3 -#define TINYFORMAT_PASSARGS_TAIL_4 , v2, v3, v4 -#define TINYFORMAT_PASSARGS_TAIL_5 , v2, v3, v4, v5 -#define TINYFORMAT_PASSARGS_TAIL_6 , v2, v3, v4, v5, v6 -#define TINYFORMAT_PASSARGS_TAIL_7 , v2, v3, v4, v5, v6, v7 -#define TINYFORMAT_PASSARGS_TAIL_8 , v2, v3, v4, v5, v6, v7, v8 -#define TINYFORMAT_PASSARGS_TAIL_9 , v2, v3, v4, v5, v6, v7, v8, v9 -#define TINYFORMAT_PASSARGS_TAIL_10 , v2, v3, v4, v5, v6, v7, v8, v9, v10 -#define TINYFORMAT_PASSARGS_TAIL_11 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 -#define TINYFORMAT_PASSARGS_TAIL_12 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 -#define TINYFORMAT_PASSARGS_TAIL_13 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 -#define TINYFORMAT_PASSARGS_TAIL_14 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 -#define TINYFORMAT_PASSARGS_TAIL_15 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 -#define TINYFORMAT_PASSARGS_TAIL_16 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 - -#define TINYFORMAT_FOREACH_ARGNUM(m) \ - m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) m(9) m(10) m(11) m(12) m(13) m(14) m(15) m(16) -//[[[end]]] - - - -namespace detail { - -// Type-opaque holder for an argument to format(), with associated actions on -// the type held as explicit function pointers. This allows FormatArg's for -// each argument to be allocated as a homogenous array inside FormatList -// whereas a naive implementation based on inheritance does not. -class FormatArg -{ - public: - FormatArg() {} - - template - FormatArg(const T& value) - : m_value(static_cast(&value)), - m_formatImpl(&formatImpl), - m_toIntImpl(&toIntImpl) - { } - - void format(std::ostream& out, const char* fmtBegin, - const char* fmtEnd, int ntrunc) const - { - m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value); - } - - int toInt() const - { - return m_toIntImpl(m_value); - } - - private: - template - TINYFORMAT_HIDDEN static void formatImpl(std::ostream& out, const char* fmtBegin, - const char* fmtEnd, int ntrunc, const void* value) - { - formatValue(out, fmtBegin, fmtEnd, ntrunc, *static_cast(value)); - } - - template - TINYFORMAT_HIDDEN static int toIntImpl(const void* value) - { - return convertToInt::invoke(*static_cast(value)); - } - - const void* m_value; - void (*m_formatImpl)(std::ostream& out, const char* fmtBegin, - const char* fmtEnd, int ntrunc, const void* value); - int (*m_toIntImpl)(const void* value); -}; - - -// Parse and return an integer from the string c, as atoi() -// On return, c is set to one past the end of the integer. -inline int parseIntAndAdvance(const char*& c) -{ - int i = 0; - for(;*c >= '0' && *c <= '9'; ++c) - i = 10*i + (*c - '0'); - return i; -} - -// Print literal part of format string and return next format spec -// position. -// -// Skips over any occurrences of '%%', printing a literal '%' to the -// output. The position of the first % character of the next -// nontrivial format spec is returned, or the end of string. -inline const char* printFormatStringLiteral(std::ostream& out, const char* fmt) -{ - const char* c = fmt; - for(;; ++c) - { - switch(*c) - { - case '\0': - out.write(fmt, c - fmt); - return c; - case '%': - out.write(fmt, c - fmt); - if(*(c+1) != '%') - return c; - // for "%%", tack trailing % onto next literal section. - fmt = ++c; - break; - default: - break; - } - } -} - - -// Parse a format string and set the stream state accordingly. -// -// The format mini-language recognized here is meant to be the one from C99, -// with the form "%[flags][width][.precision][length]type". -// -// Formatting options which can't be natively represented using the ostream -// state are returned in spacePadPositive (for space padded positive numbers) -// and ntrunc (for truncating conversions). argIndex is incremented if -// necessary to pull out variable width and precision. The function returns a -// pointer to the character after the end of the current format spec. -inline const char* streamStateFromFormat(std::ostream& out, bool& spacePadPositive, - int& ntrunc, const char* fmtStart, - const detail::FormatArg* formatters, - int& argIndex, int numFormatters) -{ - if(*fmtStart != '%') - { - TINYFORMAT_ERROR("tinyformat: Not enough conversion specifiers in format string"); - return fmtStart; - } - // Reset stream state to defaults. - out.width(0); - out.precision(6); - out.fill(' '); - // Reset most flags; ignore irrelevant unitbuf & skipws. - out.unsetf(std::ios::adjustfield | std::ios::basefield | - std::ios::floatfield | std::ios::showbase | std::ios::boolalpha | - std::ios::showpoint | std::ios::showpos | std::ios::uppercase); - bool precisionSet = false; - bool widthSet = false; - int widthExtra = 0; - const char* c = fmtStart + 1; - // 1) Parse flags - for(;; ++c) - { - switch(*c) - { - case '#': - out.setf(std::ios::showpoint | std::ios::showbase); - continue; - case '0': - // overridden by left alignment ('-' flag) - if(!(out.flags() & std::ios::left)) - { - // Use internal padding so that numeric values are - // formatted correctly, eg -00010 rather than 000-10 - out.fill('0'); - out.setf(std::ios::internal, std::ios::adjustfield); - } - continue; - case '-': - out.fill(' '); - out.setf(std::ios::left, std::ios::adjustfield); - continue; - case ' ': - // overridden by show positive sign, '+' flag. - if(!(out.flags() & std::ios::showpos)) - spacePadPositive = true; - continue; - case '+': - out.setf(std::ios::showpos); - spacePadPositive = false; - widthExtra = 1; - continue; - default: - break; - } - break; - } - // 2) Parse width - if(*c >= '0' && *c <= '9') - { - widthSet = true; - out.width(parseIntAndAdvance(c)); - } - if(*c == '*') - { - widthSet = true; - int width = 0; - if(argIndex < numFormatters) - width = formatters[argIndex++].toInt(); - else - TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable width"); - if(width < 0) - { - // negative widths correspond to '-' flag set - out.fill(' '); - out.setf(std::ios::left, std::ios::adjustfield); - width = -width; - } - out.width(width); - ++c; - } - // 3) Parse precision - if(*c == '.') - { - ++c; - int precision = 0; - if(*c == '*') - { - ++c; - if(argIndex < numFormatters) - precision = formatters[argIndex++].toInt(); - else - TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable precision"); - } - else - { - if(*c >= '0' && *c <= '9') - precision = parseIntAndAdvance(c); - else if(*c == '-') // negative precisions ignored, treated as zero. - parseIntAndAdvance(++c); - } - out.precision(precision); - precisionSet = true; - } - // 4) Ignore any C99 length modifier - while(*c == 'l' || *c == 'h' || *c == 'L' || - *c == 'j' || *c == 'z' || *c == 't') - ++c; - // 5) We're up to the conversion specifier character. - // Set stream flags based on conversion specifier (thanks to the - // boost::format class for forging the way here). - bool intConversion = false; - switch(*c) - { - case 'u': case 'd': case 'i': - out.setf(std::ios::dec, std::ios::basefield); - intConversion = true; - break; - case 'o': - out.setf(std::ios::oct, std::ios::basefield); - intConversion = true; - break; - case 'X': - out.setf(std::ios::uppercase); - case 'x': case 'p': - out.setf(std::ios::hex, std::ios::basefield); - intConversion = true; - break; - case 'E': - out.setf(std::ios::uppercase); - case 'e': - out.setf(std::ios::scientific, std::ios::floatfield); - out.setf(std::ios::dec, std::ios::basefield); - break; - case 'F': - out.setf(std::ios::uppercase); - case 'f': - out.setf(std::ios::fixed, std::ios::floatfield); - break; - case 'G': - out.setf(std::ios::uppercase); - case 'g': - out.setf(std::ios::dec, std::ios::basefield); - // As in boost::format, let stream decide float format. - out.flags(out.flags() & ~std::ios::floatfield); - break; - case 'a': case 'A': - TINYFORMAT_ERROR("tinyformat: the %a and %A conversion specs " - "are not supported"); - break; - case 'c': - // Handled as special case inside formatValue() - break; - case 's': - if(precisionSet) - ntrunc = static_cast(out.precision()); - // Make %s print booleans as "true" and "false" - out.setf(std::ios::boolalpha); - break; - case 'n': - // Not supported - will cause problems! - TINYFORMAT_ERROR("tinyformat: %n conversion spec not supported"); - break; - case '\0': - TINYFORMAT_ERROR("tinyformat: Conversion spec incorrectly " - "terminated by end of string"); - return c; - default: - break; - } - if(intConversion && precisionSet && !widthSet) - { - // "precision" for integers gives the minimum number of digits (to be - // padded with zeros on the left). This isn't really supported by the - // iostreams, but we can approximately simulate it with the width if - // the width isn't otherwise used. - out.width(out.precision() + widthExtra); - out.setf(std::ios::internal, std::ios::adjustfield); - out.fill('0'); - } - return c+1; -} - - -//------------------------------------------------------------------------------ -inline void formatImpl(std::ostream& out, const char* fmt, - const detail::FormatArg* formatters, - int numFormatters) -{ - // Saved stream state - std::streamsize origWidth = out.width(); - std::streamsize origPrecision = out.precision(); - std::ios::fmtflags origFlags = out.flags(); - char origFill = out.fill(); - - for (int argIndex = 0; argIndex < numFormatters; ++argIndex) - { - // Parse the format string - fmt = printFormatStringLiteral(out, fmt); - bool spacePadPositive = false; - int ntrunc = -1; - const char* fmtEnd = streamStateFromFormat(out, spacePadPositive, ntrunc, fmt, - formatters, argIndex, numFormatters); - if (argIndex >= numFormatters) - { - // Check args remain after reading any variable width/precision - TINYFORMAT_ERROR("tinyformat: Not enough format arguments"); - return; - } - const FormatArg& arg = formatters[argIndex]; - // Format the arg into the stream. - if(!spacePadPositive) - arg.format(out, fmt, fmtEnd, ntrunc); - else - { - // The following is a special case with no direct correspondence - // between stream formatting and the printf() behaviour. Simulate - // it crudely by formatting into a temporary string stream and - // munging the resulting string. - std::ostringstream tmpStream; - tmpStream.copyfmt(out); - tmpStream.setf(std::ios::showpos); - arg.format(tmpStream, fmt, fmtEnd, ntrunc); - std::string result = tmpStream.str(); // allocates... yuck. - for(size_t i = 0, iend = result.size(); i < iend; ++i) - if(result[i] == '+') result[i] = ' '; - out << result; - } - fmt = fmtEnd; - } - - // Print remaining part of format string. - fmt = printFormatStringLiteral(out, fmt); - if(*fmt != '\0') - TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string"); - - // Restore stream state - out.width(origWidth); - out.precision(origPrecision); - out.flags(origFlags); - out.fill(origFill); -} - -} // namespace detail - - -/// List of template arguments format(), held in a type-opaque way. -/// -/// A const reference to FormatList (typedef'd as FormatListRef) may be -/// conveniently used to pass arguments to non-template functions: All type -/// information has been stripped from the arguments, leaving just enough of a -/// common interface to perform formatting as required. -class FormatList -{ - public: - FormatList(detail::FormatArg* formatters, int N) - : m_formatters(formatters), m_N(N) { } - - friend void vformat(std::ostream& out, const char* fmt, - const FormatList& list); - - private: - const detail::FormatArg* m_formatters; - int m_N; -}; - -/// Reference to type-opaque format list for passing to vformat() -typedef const FormatList& FormatListRef; - - -namespace detail { - -// Format list subclass with fixed storage to avoid dynamic allocation -template -class FormatListN : public FormatList -{ - public: -#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES - template - FormatListN(const Args&... args) - : FormatList(&m_formatterStore[0], N), - m_formatterStore { FormatArg(args)... } - { static_assert(sizeof...(args) == N, "Number of args must be N"); } -#else // C++98 version - void init(int) {} -# define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n) \ - \ - template \ - FormatListN(TINYFORMAT_VARARGS(n)) \ - : FormatList(&m_formatterStore[0], n) \ - { assert(n == N); init(0, TINYFORMAT_PASSARGS(n)); } \ - \ - template \ - void init(int i, TINYFORMAT_VARARGS(n)) \ - { \ - m_formatterStore[i] = FormatArg(v1); \ - init(i+1 TINYFORMAT_PASSARGS_TAIL(n)); \ - } - - TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR) -# undef TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR -#endif - - private: - FormatArg m_formatterStore[N]; -}; - -// Special 0-arg version - MSVC says zero-sized C array in struct is nonstandard -template<> class FormatListN<0> : public FormatList -{ - public: FormatListN() : FormatList(0, 0) {} -}; - -} // namespace detail - - -//------------------------------------------------------------------------------ -// Primary API functions - -#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES - -/// Make type-agnostic format list from list of template arguments. -/// -/// The exact return type of this function is an implementation detail and -/// shouldn't be relied upon. Instead it should be stored as a FormatListRef: -/// -/// FormatListRef formatList = makeFormatList( /*...*/ ); -template -detail::FormatListN makeFormatList(const Args&... args) -{ - return detail::FormatListN(args...); -} - -#else // C++98 version - -inline detail::FormatListN<0> makeFormatList() -{ - return detail::FormatListN<0>(); -} -#define TINYFORMAT_MAKE_MAKEFORMATLIST(n) \ -template \ -detail::FormatListN makeFormatList(TINYFORMAT_VARARGS(n)) \ -{ \ - return detail::FormatListN(TINYFORMAT_PASSARGS(n)); \ -} -TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_MAKEFORMATLIST) -#undef TINYFORMAT_MAKE_MAKEFORMATLIST - -#endif - -/// Format list of arguments to the stream according to the given format string. -/// -/// The name vformat() is chosen for the semantic similarity to vprintf(): the -/// list of format arguments is held in a single function argument. -inline void vformat(std::ostream& out, const char* fmt, FormatListRef list) -{ - detail::formatImpl(out, fmt, list.m_formatters, list.m_N); -} - - -#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES - -/// Format list of arguments to the stream according to given format string. -template -void format(std::ostream& out, const char* fmt, const Args&... args) -{ - vformat(out, fmt, makeFormatList(args...)); -} - -/// Format list of arguments according to the given format string and return -/// the result as a string. -template -std::string format(const char* fmt, const Args&... args) -{ - std::ostringstream oss; - format(oss, fmt, args...); - return oss.str(); -} - -/// Format list of arguments to std::cout, according to the given format string -template -void printf(const char* fmt, const Args&... args) -{ - format(std::cout, fmt, args...); -} - -template -void printfln(const char* fmt, const Args&... args) -{ - format(std::cout, fmt, args...); - std::cout << '\n'; -} - -#else // C++98 version - -inline void format(std::ostream& out, const char* fmt) -{ - vformat(out, fmt, makeFormatList()); -} - -inline std::string format(const char* fmt) -{ - std::ostringstream oss; - format(oss, fmt); - return oss.str(); -} - -inline void printf(const char* fmt) -{ - format(std::cout, fmt); -} - -inline void printfln(const char* fmt) -{ - format(std::cout, fmt); - std::cout << '\n'; -} - -#define TINYFORMAT_MAKE_FORMAT_FUNCS(n) \ - \ -template \ -void format(std::ostream& out, const char* fmt, TINYFORMAT_VARARGS(n)) \ -{ \ - vformat(out, fmt, makeFormatList(TINYFORMAT_PASSARGS(n))); \ -} \ - \ -template \ -std::string format(const char* fmt, TINYFORMAT_VARARGS(n)) \ -{ \ - std::ostringstream oss; \ - format(oss, fmt, TINYFORMAT_PASSARGS(n)); \ - return oss.str(); \ -} \ - \ -template \ -void printf(const char* fmt, TINYFORMAT_VARARGS(n)) \ -{ \ - format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \ -} \ - \ -template \ -void printfln(const char* fmt, TINYFORMAT_VARARGS(n)) \ -{ \ - format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \ - std::cout << '\n'; \ -} - -TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS) -#undef TINYFORMAT_MAKE_FORMAT_FUNCS - -#endif - -// Added for Bitcoin Core -template -std::string format(const std::string &fmt, const Args&... args) -{ - std::ostringstream oss; - format(oss, fmt.c_str(), args...); - return oss.str(); -} - -} // namespace tinyformat - -#define strprintf tfm::format - -#endif // TINYFORMAT_H_INCLUDED diff --git a/src/Native/libbeamhash/uint256.cpp b/src/Native/libbeamhash/uint256.cpp deleted file mode 100644 index 25148808c6..0000000000 --- a/src/Native/libbeamhash/uint256.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "uint256.h" - -#include "utilstrencodings.h" - -#include -#include - -template -base_blob::base_blob(const std::vector& vch) -{ - assert(vch.size() == sizeof(data)); - memcpy(data, &vch[0], sizeof(data)); -} - -template -std::string base_blob::GetHex() const -{ - char psz[sizeof(data) * 2 + 1]; - for (unsigned int i = 0; i < sizeof(data); i++) - sprintf(psz + i * 2, "%02x", data[sizeof(data) - i - 1]); - return std::string(psz, psz + sizeof(data) * 2); -} - -template -void base_blob::SetHex(const char* psz) -{ - memset(data, 0, sizeof(data)); - - // skip leading spaces - while (isspace(*psz)) - psz++; - - // skip 0x - if (psz[0] == '0' && tolower(psz[1]) == 'x') - psz += 2; - - // hex string to uint - const char* pbegin = psz; - while (::HexDigit(*psz) != -1) - psz++; - psz--; - unsigned char* p1 = (unsigned char*)data; - unsigned char* pend = p1 + WIDTH; - while (psz >= pbegin && p1 < pend) { - *p1 = ::HexDigit(*psz--); - if (psz >= pbegin) { - *p1 |= ((unsigned char)::HexDigit(*psz--) << 4); - p1++; - } - } -} - -template -void base_blob::SetHex(const std::string& str) -{ - SetHex(str.c_str()); -} - -template -std::string base_blob::ToString() const -{ - return (GetHex()); -} - -// Explicit instantiations for base_blob<160> -template base_blob<160>::base_blob(const std::vector&); -template std::string base_blob<160>::GetHex() const; -template std::string base_blob<160>::ToString() const; -template void base_blob<160>::SetHex(const char*); -template void base_blob<160>::SetHex(const std::string&); - -// Explicit instantiations for base_blob<256> -template base_blob<256>::base_blob(const std::vector&); -template std::string base_blob<256>::GetHex() const; -template std::string base_blob<256>::ToString() const; -template void base_blob<256>::SetHex(const char*); -template void base_blob<256>::SetHex(const std::string&); - -static void inline HashMix(uint32_t& a, uint32_t& b, uint32_t& c) -{ - // Taken from lookup3, by Bob Jenkins. - a -= c; - a ^= ((c << 4) | (c >> 28)); - c += b; - b -= a; - b ^= ((a << 6) | (a >> 26)); - a += c; - c -= b; - c ^= ((b << 8) | (b >> 24)); - b += a; - a -= c; - a ^= ((c << 16) | (c >> 16)); - c += b; - b -= a; - b ^= ((a << 19) | (a >> 13)); - a += c; - c -= b; - c ^= ((b << 4) | (b >> 28)); - b += a; -} - -static void inline HashFinal(uint32_t& a, uint32_t& b, uint32_t& c) -{ - // Taken from lookup3, by Bob Jenkins. - c ^= b; - c -= ((b << 14) | (b >> 18)); - a ^= c; - a -= ((c << 11) | (c >> 21)); - b ^= a; - b -= ((a << 25) | (a >> 7)); - c ^= b; - c -= ((b << 16) | (b >> 16)); - a ^= c; - a -= ((c << 4) | (c >> 28)); - b ^= a; - b -= ((a << 14) | (a >> 18)); - c ^= b; - c -= ((b << 24) | (b >> 8)); -} - -uint64_t uint256::GetHash(const uint256& salt) const -{ - uint32_t a, b, c; - const uint32_t *pn = (const uint32_t*)data; - const uint32_t *salt_pn = (const uint32_t*)salt.data; - a = b = c = 0xdeadbeef + WIDTH; - - a += pn[0] ^ salt_pn[0]; - b += pn[1] ^ salt_pn[1]; - c += pn[2] ^ salt_pn[2]; - HashMix(a, b, c); - a += pn[3] ^ salt_pn[3]; - b += pn[4] ^ salt_pn[4]; - c += pn[5] ^ salt_pn[5]; - HashMix(a, b, c); - a += pn[6] ^ salt_pn[6]; - b += pn[7] ^ salt_pn[7]; - HashFinal(a, b, c); - - return ((((uint64_t)b) << 32) | c); -} diff --git a/src/Native/libbeamhash/uint256.h b/src/Native/libbeamhash/uint256.h deleted file mode 100644 index 3729c981a1..0000000000 --- a/src/Native/libbeamhash/uint256.h +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_UINT256_H -#define BITCOIN_UINT256_H - -#include -#include -#include -#include -#include -#include - -/** Template base class for fixed-sized opaque blobs. */ -template -class base_blob -{ -protected: - enum { WIDTH=BITS/8 }; - alignas(uint32_t) uint8_t data[WIDTH]; -public: - base_blob() - { - memset(data, 0, sizeof(data)); - } - - explicit base_blob(const std::vector& vch); - - bool IsNull() const - { - for (int i = 0; i < WIDTH; i++) - if (data[i] != 0) - return false; - return true; - } - - void SetNull() - { - memset(data, 0, sizeof(data)); - } - - friend inline bool operator==(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) == 0; } - friend inline bool operator!=(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) != 0; } - friend inline bool operator<(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) < 0; } - - std::string GetHex() const; - void SetHex(const char* psz); - void SetHex(const std::string& str); - std::string ToString() const; - - unsigned char* begin() - { - return &data[0]; - } - - unsigned char* end() - { - return &data[WIDTH]; - } - - const unsigned char* begin() const - { - return &data[0]; - } - - const unsigned char* end() const - { - return &data[WIDTH]; - } - - unsigned int size() const - { - return sizeof(data); - } - - unsigned int GetSerializeSize(int nType, int nVersion) const - { - return sizeof(data); - } - - template - void Serialize(Stream& s, int nType, int nVersion) const - { - s.write((char*)data, sizeof(data)); - } - - template - void Unserialize(Stream& s, int nType, int nVersion) - { - s.read((char*)data, sizeof(data)); - } -}; - -/** 160-bit opaque blob. - * @note This type is called uint160 for historical reasons only. It is an opaque - * blob of 160 bits and has no integer operations. - */ -class uint160 : public base_blob<160> { -public: - uint160() {} - uint160(const base_blob<160>& b) : base_blob<160>(b) {} - explicit uint160(const std::vector& vch) : base_blob<160>(vch) {} -}; - -/** 256-bit opaque blob. - * @note This type is called uint256 for historical reasons only. It is an - * opaque blob of 256 bits and has no integer operations. Use arith_uint256 if - * those are required. - */ -class uint256 : public base_blob<256> { -public: - uint256() {} - uint256(const base_blob<256>& b) : base_blob<256>(b) {} - explicit uint256(const std::vector& vch) : base_blob<256>(vch) {} - - /** A cheap hash function that just returns 64 bits from the result, it can be - * used when the contents are considered uniformly random. It is not appropriate - * when the value can easily be influenced from outside as e.g. a network adversary could - * provide values to trigger worst-case behavior. - * @note The result of this function is not stable between little and big endian. - */ - uint64_t GetCheapHash() const - { - uint64_t result; - memcpy((void*)&result, (void*)data, 8); - return result; - } - - /** A more secure, salted hash function. - * @note This hash is not stable between little and big endian. - */ - uint64_t GetHash(const uint256& salt) const; -}; - -/* uint256 from const char *. - * This is a separate function because the constructor uint256(const char*) can result - * in dangerously catching uint256(0). - */ -inline uint256 uint256S(const char *str) -{ - uint256 rv; - rv.SetHex(str); - return rv; -} -/* uint256 from std::string. - * This is a separate function because the constructor uint256(const std::string &str) can result - * in dangerously catching uint256(0) via std::string(const char*). - */ -inline uint256 uint256S(const std::string& str) -{ - uint256 rv; - rv.SetHex(str); - return rv; -} - -#endif // BITCOIN_UINT256_H diff --git a/src/Native/libbeamhash/util.cpp b/src/Native/libbeamhash/util.cpp deleted file mode 100644 index e59783e993..0000000000 --- a/src/Native/libbeamhash/util.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - -#include "util.h" -#include "random.h" -#include "serialize.h" -#include "utilstrencodings.h" - -#include - -#ifndef WIN32 -// for posix_fallocate -#ifdef __linux__ - -#ifdef _POSIX_C_SOURCE -#undef _POSIX_C_SOURCE -#endif - -#define _POSIX_C_SOURCE 200112L - -#endif // __linux__ - -#include -#include -#include -#include - -#else - -#ifdef _MSC_VER -#pragma warning(disable:4786) -#pragma warning(disable:4804) -#pragma warning(disable:4805) -#pragma warning(disable:4717) -#endif - -#ifdef _WIN32_WINNT -#undef _WIN32_WINNT -#endif -#define _WIN32_WINNT 0x0501 - -#ifdef _WIN32_IE -#undef _WIN32_IE -#endif -#define _WIN32_IE 0x0501 - -#define WIN32_LEAN_AND_MEAN 1 -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#include /* for _commit */ -#include -#endif - - -using namespace std; - -bool fDebug = false; -bool fLogTimestamps = true; -bool fLogTimeMicros = false; - - - -int LogPrintStr(const std::string &str) -{ - int ret = 0; // Returns total number of characters written - // print to console - ret = fwrite(str.data(), 1, str.size(), stdout); - fflush(stdout); - return ret; -} - diff --git a/src/Native/libbeamhash/util.h b/src/Native/libbeamhash/util.h deleted file mode 100644 index 6a2f92f1ef..0000000000 --- a/src/Native/libbeamhash/util.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -/** - * Server/client environment: argument handling, config file parsing, - * logging, thread wrappers - */ -#ifndef BITCOIN_UTIL_H -#define BITCOIN_UTIL_H - -#include "tinyformat.h" -#include - - - -/** Send a string to the log output */ -int LogPrintStr(const std::string &str); - -#define LogPrintf(...) LogPrint(NULL, __VA_ARGS__) - -/** - * When we switch to C++11, this can be switched to variadic templates instead - * of this macro-based construction (see tinyformat.h). - */ -#define MAKE_ERROR_AND_LOG_FUNC(n) \ - /** Print to debug.log if -debug=category switch is given OR category is NULL. */ \ - template \ - static inline int LogPrint(const char* category, const char* format, TINYFORMAT_VARARGS(n)) \ - { \ - return LogPrintStr(tfm::format(format, TINYFORMAT_PASSARGS(n))); \ - } \ - /** Log error and return false */ \ - template \ - static inline bool error(const char* format, TINYFORMAT_VARARGS(n)) \ - { \ - LogPrintStr("ERROR: " + tfm::format(format, TINYFORMAT_PASSARGS(n)) + "\n"); \ - return false; \ - } - -TINYFORMAT_FOREACH_ARGNUM(MAKE_ERROR_AND_LOG_FUNC) - -/** - * Zero-arg versions of logging and error, these are not covered by - * TINYFORMAT_FOREACH_ARGNUM - */ -static inline int LogPrint(const char* category, const char* format) -{ - return LogPrintStr(format); -} -static inline bool error(const char* format) -{ - return LogPrintStr(std::string("ERROR: ") + format + "\n"); -} - - -#endif // BITCOIN_UTIL_H diff --git a/src/Native/libbeamhash/utilstrencodings.cpp b/src/Native/libbeamhash/utilstrencodings.cpp deleted file mode 100644 index 0a5fbb3d28..0000000000 --- a/src/Native/libbeamhash/utilstrencodings.cpp +++ /dev/null @@ -1,692 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "utilstrencodings.h" - -#include "tinyformat.h" - -#include -#include -#include -#include -#include - -using namespace std; - -string SanitizeString(const string& str) -{ - /** - * safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything - * even possibly remotely dangerous like & or > - */ - static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@()"); - string strResult; - for (std::string::size_type i = 0; i < str.size(); i++) - { - if (safeChars.find(str[i]) != std::string::npos) - strResult.push_back(str[i]); - } - return strResult; -} - -string SanitizeFilename(const string& str) -{ - /** - * safeChars chosen to restrict filename, keeping it simple to avoid cross-platform issues. - * http://stackoverflow.com/a/2306003 - */ - static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890"); - string strResult; - for (std::string::size_type i = 0; i < str.size(); i++) - { - if (safeChars.find(str[i]) != std::string::npos) - strResult.push_back(str[i]); - } - return strResult; -} - -std::string HexInt(uint32_t val) -{ - std::stringstream ss; - ss << std::setfill('0') << std::setw(sizeof(uint32_t) * 2) << std::hex << val; - return ss.str(); -} - -uint32_t ParseHexToUInt32(const std::string& str) { - std::istringstream converter(str); - uint32_t value; - converter >> std::hex >> value; - return value; -} - -const signed char p_util_hexdigit[256] = -{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, - -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; - -signed char HexDigit(char c) -{ - return p_util_hexdigit[(unsigned char)c]; -} - -bool IsHex(const string& str) -{ - for(std::string::const_iterator it(str.begin()); it != str.end(); ++it) - { - if (HexDigit(*it) < 0) - return false; - } - return (str.size() > 0) && (str.size()%2 == 0); -} - -vector ParseHex(const char* psz) -{ - // convert hex dump to vector - vector vch; - while (true) - { - while (isspace(*psz)) - psz++; - signed char c = HexDigit(*psz++); - if (c == (signed char)-1) - break; - unsigned char n = (c << 4); - c = HexDigit(*psz++); - if (c == (signed char)-1) - break; - n |= c; - vch.push_back(n); - } - return vch; -} - -vector ParseHex(const string& str) -{ - return ParseHex(str.c_str()); -} - -string EncodeBase64(const unsigned char* pch, size_t len) -{ - static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - string strRet=""; - strRet.reserve((len+2)/3*4); - - int mode=0, left=0; - const unsigned char *pchEnd = pch+len; - - while (pch> 2]; - left = (enc & 3) << 4; - mode = 1; - break; - - case 1: // we have two bits - strRet += pbase64[left | (enc >> 4)]; - left = (enc & 15) << 2; - mode = 2; - break; - - case 2: // we have four bits - strRet += pbase64[left | (enc >> 6)]; - strRet += pbase64[enc & 63]; - mode = 0; - break; - } - } - - if (mode) - { - strRet += pbase64[left]; - strRet += '='; - if (mode == 1) - strRet += '='; - } - - return strRet; -} - -string EncodeBase64(const string& str) -{ - return EncodeBase64((const unsigned char*)str.c_str(), str.size()); -} - -vector DecodeBase64(const char* p, bool* pfInvalid) -{ - static const int decode64_table[256] = - { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, - -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - - if (pfInvalid) - *pfInvalid = false; - - vector vchRet; - vchRet.reserve(strlen(p)*3/4); - - int mode = 0; - int left = 0; - - while (1) - { - int dec = decode64_table[(unsigned char)*p]; - if (dec == -1) break; - p++; - switch (mode) - { - case 0: // we have no bits and get 6 - left = dec; - mode = 1; - break; - - case 1: // we have 6 bits and keep 4 - vchRet.push_back((left<<2) | (dec>>4)); - left = dec & 15; - mode = 2; - break; - - case 2: // we have 4 bits and get 6, we keep 2 - vchRet.push_back((left<<4) | (dec>>2)); - left = dec & 3; - mode = 3; - break; - - case 3: // we have 2 bits and get 6 - vchRet.push_back((left<<6) | dec); - mode = 0; - break; - } - } - - if (pfInvalid) - switch (mode) - { - case 0: // 4n base64 characters processed: ok - break; - - case 1: // 4n+1 base64 character processed: impossible - *pfInvalid = true; - break; - - case 2: // 4n+2 base64 characters processed: require '==' - if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1) - *pfInvalid = true; - break; - - case 3: // 4n+3 base64 characters processed: require '=' - if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1) - *pfInvalid = true; - break; - } - - return vchRet; -} - -string DecodeBase64(const string& str) -{ - vector vchRet = DecodeBase64(str.c_str()); - return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size()); -} - -string EncodeBase32(const unsigned char* pch, size_t len) -{ - static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; - - string strRet=""; - strRet.reserve((len+4)/5*8); - - int mode=0, left=0; - const unsigned char *pchEnd = pch+len; - - while (pch> 3]; - left = (enc & 7) << 2; - mode = 1; - break; - - case 1: // we have three bits - strRet += pbase32[left | (enc >> 6)]; - strRet += pbase32[(enc >> 1) & 31]; - left = (enc & 1) << 4; - mode = 2; - break; - - case 2: // we have one bit - strRet += pbase32[left | (enc >> 4)]; - left = (enc & 15) << 1; - mode = 3; - break; - - case 3: // we have four bits - strRet += pbase32[left | (enc >> 7)]; - strRet += pbase32[(enc >> 2) & 31]; - left = (enc & 3) << 3; - mode = 4; - break; - - case 4: // we have two bits - strRet += pbase32[left | (enc >> 5)]; - strRet += pbase32[enc & 31]; - mode = 0; - } - } - - static const int nPadding[5] = {0, 6, 4, 3, 1}; - if (mode) - { - strRet += pbase32[left]; - for (int n=0; n DecodeBase32(const char* p, bool* pfInvalid) -{ - static const int decode32_table[256] = - { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - - if (pfInvalid) - *pfInvalid = false; - - vector vchRet; - vchRet.reserve((strlen(p))*5/8); - - int mode = 0; - int left = 0; - - while (1) - { - int dec = decode32_table[(unsigned char)*p]; - if (dec == -1) break; - p++; - switch (mode) - { - case 0: // we have no bits and get 5 - left = dec; - mode = 1; - break; - - case 1: // we have 5 bits and keep 2 - vchRet.push_back((left<<3) | (dec>>2)); - left = dec & 3; - mode = 2; - break; - - case 2: // we have 2 bits and keep 7 - left = left << 5 | dec; - mode = 3; - break; - - case 3: // we have 7 bits and keep 4 - vchRet.push_back((left<<1) | (dec>>4)); - left = dec & 15; - mode = 4; - break; - - case 4: // we have 4 bits, and keep 1 - vchRet.push_back((left<<4) | (dec>>1)); - left = dec & 1; - mode = 5; - break; - - case 5: // we have 1 bit, and keep 6 - left = left << 5 | dec; - mode = 6; - break; - - case 6: // we have 6 bits, and keep 3 - vchRet.push_back((left<<2) | (dec>>3)); - left = dec & 7; - mode = 7; - break; - - case 7: // we have 3 bits, and keep 0 - vchRet.push_back((left<<5) | dec); - mode = 0; - break; - } - } - - if (pfInvalid) - switch (mode) - { - case 0: // 8n base32 characters processed: ok - break; - - case 1: // 8n+1 base32 characters processed: impossible - case 3: // +3 - case 6: // +6 - *pfInvalid = true; - break; - - case 2: // 8n+2 base32 characters processed: require '======' - if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1) - *pfInvalid = true; - break; - - case 4: // 8n+4 base32 characters processed: require '====' - if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1) - *pfInvalid = true; - break; - - case 5: // 8n+5 base32 characters processed: require '===' - if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1) - *pfInvalid = true; - break; - - case 7: // 8n+7 base32 characters processed: require '=' - if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1) - *pfInvalid = true; - break; - } - - return vchRet; -} - -string DecodeBase32(const string& str) -{ - vector vchRet = DecodeBase32(str.c_str()); - return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size()); -} - -static bool ParsePrechecks(const std::string& str) -{ - if (str.empty()) // No empty string allowed - return false; - if (str.size() >= 1 && (isspace(str[0]) || isspace(str[str.size()-1]))) // No padding allowed - return false; - if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed - return false; - return true; -} - -bool ParseInt32(const std::string& str, int32_t *out) -{ - if (!ParsePrechecks(str)) - return false; - char *endp = NULL; - errno = 0; // strtol will not set errno if valid - long int n = strtol(str.c_str(), &endp, 10); - if(out) *out = (int32_t)n; - // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow - // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit - // platforms the size of these types may be different. - return endp && *endp == 0 && !errno && - n >= std::numeric_limits::min() && - n <= std::numeric_limits::max(); -} - -bool ParseInt64(const std::string& str, int64_t *out) -{ - if (!ParsePrechecks(str)) - return false; - char *endp = NULL; - errno = 0; // strtoll will not set errno if valid - long long int n = strtoll(str.c_str(), &endp, 10); - if(out) *out = (int64_t)n; - // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow - // we still have to check that the returned value is within the range of an *int64_t*. - return endp && *endp == 0 && !errno && - n >= std::numeric_limits::min() && - n <= std::numeric_limits::max(); -} - -bool ParseDouble(const std::string& str, double *out) -{ - if (!ParsePrechecks(str)) - return false; - if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed - return false; - std::istringstream text(str); - text.imbue(std::locale::classic()); - double result; - text >> result; - if(out) *out = result; - return text.eof() && !text.fail(); -} - -std::string FormatParagraph(const std::string& in, size_t width, size_t indent) -{ - std::stringstream out; - size_t col = 0; - size_t ptr = 0; - while(ptr < in.size()) - { - // Find beginning of next word - ptr = in.find_first_not_of(' ', ptr); - if (ptr == std::string::npos) - break; - // Find end of next word - size_t endword = in.find_first_of(' ', ptr); - if (endword == std::string::npos) - endword = in.size(); - // Add newline and indentation if this wraps over the allowed width - if (col > 0) - { - if ((col + endword - ptr) > width) - { - out << '\n'; - for(size_t i=0; i (UPPER_BOUND / 10LL)) - return false; /* overflow */ - mantissa *= 10; - } - mantissa += ch - '0'; - mantissa_tzeros = 0; - } - return true; -} - -bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out) -{ - int64_t mantissa = 0; - int64_t exponent = 0; - int mantissa_tzeros = 0; - bool mantissa_sign = false; - bool exponent_sign = false; - int ptr = 0; - int end = val.size(); - int point_ofs = 0; - - if (ptr < end && val[ptr] == '-') { - mantissa_sign = true; - ++ptr; - } - if (ptr < end) - { - if (val[ptr] == '0') { - /* pass single 0 */ - ++ptr; - } else if (val[ptr] >= '1' && val[ptr] <= '9') { - while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { - if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros)) - return false; /* overflow */ - ++ptr; - } - } else return false; /* missing expected digit */ - } else return false; /* empty string or loose '-' */ - if (ptr < end && val[ptr] == '.') - { - ++ptr; - if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') - { - while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { - if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros)) - return false; /* overflow */ - ++ptr; - ++point_ofs; - } - } else return false; /* missing expected digit */ - } - if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E')) - { - ++ptr; - if (ptr < end && val[ptr] == '+') - ++ptr; - else if (ptr < end && val[ptr] == '-') { - exponent_sign = true; - ++ptr; - } - if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { - while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { - if (exponent > (UPPER_BOUND / 10LL)) - return false; /* overflow */ - exponent = exponent * 10 + val[ptr] - '0'; - ++ptr; - } - } else return false; /* missing expected digit */ - } - if (ptr != end) - return false; /* trailing garbage */ - - /* finalize exponent */ - if (exponent_sign) - exponent = -exponent; - exponent = exponent - point_ofs + mantissa_tzeros; - - /* finalize mantissa */ - if (mantissa_sign) - mantissa = -mantissa; - - /* convert to one 64-bit fixed-point value */ - exponent += decimals; - if (exponent < 0) - return false; /* cannot represent values smaller than 10^-decimals */ - if (exponent >= 18) - return false; /* cannot represent values larger than or equal to 10^(18-decimals) */ - - for (int i=0; i < exponent; ++i) { - if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL)) - return false; /* overflow */ - mantissa *= 10; - } - if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND) - return false; /* overflow */ - - if (amount_out) - *amount_out = mantissa; - - return true; -} - diff --git a/src/Native/libbeamhash/utilstrencodings.h b/src/Native/libbeamhash/utilstrencodings.h deleted file mode 100644 index ccdc6a76bd..0000000000 --- a/src/Native/libbeamhash/utilstrencodings.h +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -/** - * Utilities for converting data from/to strings. - */ -#ifndef BITCOIN_UTILSTRENCODINGS_H -#define BITCOIN_UTILSTRENCODINGS_H - -#include -#include -#include - -#define BEGIN(a) ((char*)&(a)) -#define END(a) ((char*)&((&(a))[1])) -#define UBEGIN(a) ((unsigned char*)&(a)) -#define UEND(a) ((unsigned char*)&((&(a))[1])) -#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) - -/** This is needed because the foreach macro can't get over the comma in pair */ -#define PAIRTYPE(t1, t2) std::pair - -std::string SanitizeFilename(const std::string& str); -std::string SanitizeString(const std::string& str); -std::string HexInt(uint32_t val); -uint32_t ParseHexToUInt32(const std::string& str); -std::vector ParseHex(const char* psz); -std::vector ParseHex(const std::string& str); -signed char HexDigit(char c); -bool IsHex(const std::string& str); -std::vector DecodeBase64(const char* p, bool* pfInvalid = NULL); -std::string DecodeBase64(const std::string& str); -std::string EncodeBase64(const unsigned char* pch, size_t len); -std::string EncodeBase64(const std::string& str); -std::vector DecodeBase32(const char* p, bool* pfInvalid = NULL); -std::string DecodeBase32(const std::string& str); -std::string EncodeBase32(const unsigned char* pch, size_t len); -std::string EncodeBase32(const std::string& str); - -std::string i64tostr(int64_t n); -std::string itostr(int n); -int64_t atoi64(const char* psz); -int64_t atoi64(const std::string& str); -int atoi(const std::string& str); - -/** - * Convert string to signed 32-bit integer with strict parse error feedback. - * @returns true if the entire string could be parsed as valid integer, - * false if not the entire string could be parsed or when overflow or underflow occurred. - */ -bool ParseInt32(const std::string& str, int32_t *out); - -/** - * Convert string to signed 64-bit integer with strict parse error feedback. - * @returns true if the entire string could be parsed as valid integer, - * false if not the entire string could be parsed or when overflow or underflow occurred. - */ -bool ParseInt64(const std::string& str, int64_t *out); - -/** - * Convert string to double with strict parse error feedback. - * @returns true if the entire string could be parsed as valid double, - * false if not the entire string could be parsed or when overflow or underflow occurred. - */ -bool ParseDouble(const std::string& str, double *out); - -template -std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) -{ - std::string rv; - static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - rv.reserve((itend-itbegin)*3); - for(T it = itbegin; it < itend; ++it) - { - unsigned char val = (unsigned char)(*it); - if(fSpaces && it != itbegin) - rv.push_back(' '); - rv.push_back(hexmap[val>>4]); - rv.push_back(hexmap[val&15]); - } - - return rv; -} - -template -inline std::string HexStr(const T& vch, bool fSpaces=false) -{ - return HexStr(vch.begin(), vch.end(), fSpaces); -} - -/** - * Format a paragraph of text to a fixed width, adding spaces for - * indentation to any added line. - */ -std::string FormatParagraph(const std::string& in, size_t width = 79, size_t indent = 0); - -/** - * Timing-attack-resistant comparison. - * Takes time proportional to length - * of first argument. - */ -template -bool TimingResistantEqual(const T& a, const T& b) -{ - if (b.size() == 0) return a.size() == 0; - size_t accumulator = a.size() ^ b.size(); - for (size_t i = 0; i < a.size(); i++) - accumulator |= a[i] ^ b[i%b.size()]; - return accumulator == 0; -} - -/** Parse number as fixed point according to JSON number syntax. - * See http://json.org/number.gif - * @returns true on success, false on error. - * @note The result must be in the range (-10^18,10^18), otherwise an overflow error will trigger. - */ -bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out); - -#endif // BITCOIN_UTILSTRENCODINGS_H diff --git a/src/Native/libcortexcuckoocycle/Makefile b/src/Native/libcortexcuckoocycle/Makefile new file mode 100644 index 0000000000..a8f462a644 --- /dev/null +++ b/src/Native/libcortexcuckoocycle/Makefile @@ -0,0 +1,17 @@ +CFLAGS += -g -Wall -c -fPIC -O3 -Wno-format -fomit-frame-pointer $(CPU_FLAGS) -march=native +CXXFLAGS += -g -Wall -fPIC -fpermissive -O3 -Wno-format -fomit-frame-pointer -std=c++11 $(CPU_FLAGS) -march=native +LDFLAGS += -shared +LDLIBS = -lpthread +TARGET = libcortexcuckoocycle.so + +OBJECTS = crypto/blake2b-ref.o cortexcuckoocycle.o exports.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +.PHONY: clean + +clean: + $(RM) $(TARGET) $(OBJECTS) diff --git a/src/Native/libcortexcuckoocycle/cortexcuckoocycle.cpp b/src/Native/libcortexcuckoocycle/cortexcuckoocycle.cpp new file mode 100644 index 0000000000..f7c222b189 --- /dev/null +++ b/src/Native/libcortexcuckoocycle/cortexcuckoocycle.cpp @@ -0,0 +1,12 @@ +#include "cortexcuckoocycle.hpp" +#include + +#include "cuckaroo/cuckaroo.hpp" + +int32_t cortexcuckoocycle(const char *header, int headerLen, const char *solution) +{ + siphash_keys keys; + cuckaroo_cortex_setheader(header, headerLen, &keys); + int res = cuckaroo_cortex_verify((cuckaroo_cortex_word_t* )solution, keys); + return res; +} diff --git a/src/Native/libcortexcuckoocycle/cortexcuckoocycle.hpp b/src/Native/libcortexcuckoocycle/cortexcuckoocycle.hpp new file mode 100644 index 0000000000..a2ff827650 --- /dev/null +++ b/src/Native/libcortexcuckoocycle/cortexcuckoocycle.hpp @@ -0,0 +1,16 @@ +#ifndef CORTEXCUCKOOCYCLE_H +#define CORTEXCUCKOOCYCLE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t cortexcuckoocycle(const char *header, int headerLen, const char *solution); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/Native/libcortexcuckoocycle/crypto/blake2-impl.h b/src/Native/libcortexcuckoocycle/crypto/blake2-impl.h new file mode 100644 index 0000000000..5dff7fc7a3 --- /dev/null +++ b/src/Native/libcortexcuckoocycle/crypto/blake2-impl.h @@ -0,0 +1,160 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2_IMPL_H +#define BLAKE2_IMPL_H + +#include +#include + +#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) + #if defined(_MSC_VER) + #define BLAKE2_INLINE __inline + #elif defined(__GNUC__) + #define BLAKE2_INLINE __inline__ + #else + #define BLAKE2_INLINE + #endif +#else + #define BLAKE2_INLINE inline +#endif + +static BLAKE2_INLINE uint32_t load32( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint32_t )( p[0] ) << 0) | + (( uint32_t )( p[1] ) << 8) | + (( uint32_t )( p[2] ) << 16) | + (( uint32_t )( p[3] ) << 24) ; +#endif +} + +static BLAKE2_INLINE uint64_t load64( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint64_t )( p[0] ) << 0) | + (( uint64_t )( p[1] ) << 8) | + (( uint64_t )( p[2] ) << 16) | + (( uint64_t )( p[3] ) << 24) | + (( uint64_t )( p[4] ) << 32) | + (( uint64_t )( p[5] ) << 40) | + (( uint64_t )( p[6] ) << 48) | + (( uint64_t )( p[7] ) << 56) ; +#endif +} + +static BLAKE2_INLINE uint16_t load16( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint16_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint16_t )( p[0] ) << 0) | + (( uint16_t )( p[1] ) << 8) ; +#endif +} + +static BLAKE2_INLINE void store16( void *dst, uint16_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; +#endif +} + +static BLAKE2_INLINE void store32( void *dst, uint32_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); +#endif +} + +static BLAKE2_INLINE void store64( void *dst, uint64_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); + p[4] = (uint8_t)(w >> 32); + p[5] = (uint8_t)(w >> 40); + p[6] = (uint8_t)(w >> 48); + p[7] = (uint8_t)(w >> 56); +#endif +} + +static BLAKE2_INLINE uint64_t load48( const void *src ) +{ + const uint8_t *p = ( const uint8_t * )src; + return (( uint64_t )( p[0] ) << 0) | + (( uint64_t )( p[1] ) << 8) | + (( uint64_t )( p[2] ) << 16) | + (( uint64_t )( p[3] ) << 24) | + (( uint64_t )( p[4] ) << 32) | + (( uint64_t )( p[5] ) << 40) ; +} + +static BLAKE2_INLINE void store48( void *dst, uint64_t w ) +{ + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); + p[4] = (uint8_t)(w >> 32); + p[5] = (uint8_t)(w >> 40); +} + +static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 32 - c ) ); +} + +static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 64 - c ) ); +} + +/* prevents compiler optimizing out memset() */ +static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n) +{ + static void *(*const volatile memset_v)(void *, int, size_t) = &memset; + memset_v(v, 0, n); +} + +#endif diff --git a/src/Native/libbeamhash/crypto/blake/ref/blake2.h b/src/Native/libcortexcuckoocycle/crypto/blake2.h similarity index 99% rename from src/Native/libbeamhash/crypto/blake/ref/blake2.h rename to src/Native/libcortexcuckoocycle/crypto/blake2.h index 0b3296a9cc..ad62f260e7 100644 --- a/src/Native/libbeamhash/crypto/blake/ref/blake2.h +++ b/src/Native/libcortexcuckoocycle/crypto/blake2.h @@ -137,8 +137,8 @@ extern "C" { /* Padded structs result in a compile-time error */ enum { - BLAKE2_DUMMY_1 = 1/(sizeof(blake2s_param) == BLAKE2S_OUTBYTES ? 1 : 0), - BLAKE2_DUMMY_2 = 1/(sizeof(blake2b_param) == BLAKE2B_OUTBYTES ? 1 : 0) + BLAKE2_DUMMY_1 = 1/(sizeof(blake2s_param) == BLAKE2S_OUTBYTES), + BLAKE2_DUMMY_2 = 1/(sizeof(blake2b_param) == BLAKE2B_OUTBYTES) }; /* Streaming API */ diff --git a/src/Native/libbeamhash/crypto/blake/ref/blake2b-ref.c b/src/Native/libcortexcuckoocycle/crypto/blake2b-ref.c similarity index 100% rename from src/Native/libbeamhash/crypto/blake/ref/blake2b-ref.c rename to src/Native/libcortexcuckoocycle/crypto/blake2b-ref.c diff --git a/src/Native/libcortexcuckoocycle/crypto/portable_endian.h b/src/Native/libcortexcuckoocycle/crypto/portable_endian.h new file mode 100644 index 0000000000..e89694a443 --- /dev/null +++ b/src/Native/libcortexcuckoocycle/crypto/portable_endian.h @@ -0,0 +1,118 @@ +// "License": Public Domain +// I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like. +// In case there are jurisdictions that don't support putting things in the public domain you can also consider it to +// be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it +// an example on how to get the endian conversion functions on different platforms. + +#ifndef PORTABLE_ENDIAN_H__ +#define PORTABLE_ENDIAN_H__ + +#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) + +# define __WINDOWS__ + +#endif + +#if defined(__linux__) || defined(__CYGWIN__) + +# include + +#elif defined(__APPLE__) + +# include + +# define htobe16(x) OSSwapHostToBigInt16(x) +# define htole16(x) OSSwapHostToLittleInt16(x) +# define be16toh(x) OSSwapBigToHostInt16(x) +# define le16toh(x) OSSwapLittleToHostInt16(x) + +# define htobe32(x) OSSwapHostToBigInt32(x) +# define htole32(x) OSSwapHostToLittleInt32(x) +# define be32toh(x) OSSwapBigToHostInt32(x) +# define le32toh(x) OSSwapLittleToHostInt32(x) + +# define htobe64(x) OSSwapHostToBigInt64(x) +# define htole64(x) OSSwapHostToLittleInt64(x) +# define be64toh(x) OSSwapBigToHostInt64(x) +# define le64toh(x) OSSwapLittleToHostInt64(x) + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#elif defined(__OpenBSD__) + +# include + +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) + +# include + +# define be16toh(x) betoh16(x) +# define le16toh(x) letoh16(x) + +# define be32toh(x) betoh32(x) +# define le32toh(x) letoh32(x) + +# define be64toh(x) betoh64(x) +# define le64toh(x) letoh64(x) + +#elif defined(__WINDOWS__) + +# include +# include + +# if BYTE_ORDER == LITTLE_ENDIAN + +# define htobe16(x) htons(x) +# define htole16(x) (x) +# define be16toh(x) ntohs(x) +# define le16toh(x) (x) + +# define htobe32(x) htonl(x) +# define htole32(x) (x) +# define be32toh(x) ntohl(x) +# define le32toh(x) (x) + +# define htobe64(x) htonll(x) +# define htole64(x) (x) +# define be64toh(x) ntohll(x) +# define le64toh(x) (x) + +# elif BYTE_ORDER == BIG_ENDIAN + + /* that would be xbox 360 */ +# define htobe16(x) (x) +# define htole16(x) __builtin_bswap16(x) +# define be16toh(x) (x) +# define le16toh(x) __builtin_bswap16(x) + +# define htobe32(x) (x) +# define htole32(x) __builtin_bswap32(x) +# define be32toh(x) (x) +# define le32toh(x) __builtin_bswap32(x) + +# define htobe64(x) (x) +# define htole64(x) __builtin_bswap64(x) +# define be64toh(x) (x) +# define le64toh(x) __builtin_bswap64(x) + +# else + +# error byte order not supported + +# endif + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#else + +# error platform not supported + +#endif + +#endif diff --git a/src/Native/libcortexcuckoocycle/crypto/siphash.hpp b/src/Native/libcortexcuckoocycle/crypto/siphash.hpp new file mode 100644 index 0000000000..25322e90db --- /dev/null +++ b/src/Native/libcortexcuckoocycle/crypto/siphash.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include // for types uint32_t,uint64_t +#include "portable_endian.h" // for htole32/64 + +// generalize siphash by using a quadruple of 64-bit keys, +class siphash_keys { +public: + uint64_t k0; + uint64_t k1; + uint64_t k2; + uint64_t k3; + + void setkeys(const char *keybuf); + + uint64_t siphash24(const uint64_t nonce) const; +}; + +template +class siphash_state { +public: + uint64_t v0; + uint64_t v1; + uint64_t v2; + uint64_t v3; + + siphash_state(const siphash_keys &sk) { + v0 = sk.k0; v1 = sk.k1; v2 = sk.k2; v3 = sk.k3; + } + uint64_t xor_lanes() { + return (v0 ^ v1) ^ (v2 ^ v3); + } + void xor_with(const siphash_state &x) { + v0 ^= x.v0; + v1 ^= x.v1; + v2 ^= x.v2; + v3 ^= x.v3; + } + static uint64_t rotl(uint64_t x, uint64_t b) { + return (x << b) | (x >> (64 - b)); + } + void sip_round() { + v0 += v1; v2 += v3; v1 = rotl(v1,13); + v3 = rotl(v3,16); v1 ^= v0; v3 ^= v2; + v0 = rotl(v0,32); v2 += v1; v0 += v3; + v1 = rotl(v1,17); v3 = rotl(v3,rotE); + v1 ^= v2; v3 ^= v0; v2 = rotl(v2,32); + } + void hash24(const uint64_t nonce) { + v3 ^= nonce; + sip_round(); sip_round(); + v0 ^= nonce; + v2 ^= 0xff; + sip_round(); sip_round(); sip_round(); sip_round(); + } +}; + +// set siphash keys from 32 byte char array +void siphash_keys::setkeys(const char *keybuf) { + k0 = htole64(((uint64_t *)keybuf)[0]); + k1 = htole64(((uint64_t *)keybuf)[1]); + k2 = htole64(((uint64_t *)keybuf)[2]); + k3 = htole64(((uint64_t *)keybuf)[3]); +} + +uint64_t siphash_keys::siphash24(const uint64_t nonce) const { + siphash_state<> v(*this); + v.hash24(nonce); + return v.xor_lanes(); +} diff --git a/src/Native/libcortexcuckoocycle/cuckaroo/cuckaroo.hpp b/src/Native/libcortexcuckoocycle/cuckaroo/cuckaroo.hpp new file mode 100644 index 0000000000..094d95a261 --- /dev/null +++ b/src/Native/libcortexcuckoocycle/cuckaroo/cuckaroo.hpp @@ -0,0 +1,123 @@ +// Cuck(at)oo Cycle, a memory-hard proof-of-work +// Copyright (c) 2013-2019 John Tromp +#ifndef CUCKAROO_CORTEX_H +#define CUCKAROO_CORTEX_H + +#include // for types uint32_t,uint64_t +#include // for functions strlen, memset +#include +#include +#include +#include +#include "../crypto/blake2.h" +#include "../crypto/siphash.hpp" + +// save some keystrokes since i'm a lazy typer +typedef uint32_t cuckaroo_cortex_u32; +typedef uint64_t cuckaroo_cortex_u64; + +#ifndef CUCKAROO_CORTEX_MAX_SOLS +#define CUCKAROO_CORTEX_MAX_SOLS 4 +#endif + +#ifndef CUCKAROO_CORTEX_EDGE_BLOCK_BITS +#define CUCKAROO_CORTEX_EDGE_BLOCK_BITS 6 +#endif +#define CUCKAROO_CORTEX_EDGE_BLOCK_SIZE (1 << CUCKAROO_CORTEX_EDGE_BLOCK_BITS) +#define CUCKAROO_CORTEX_EDGE_BLOCK_MASK (CUCKAROO_CORTEX_EDGE_BLOCK_SIZE - 1) + +// proof-of-work parameters +#ifndef CUCKAROO_CORTEX_EDGEBITS +// the main parameter is the number of bits in an edge index, +// i.e. the 2-log of the number of edges +#define CUCKAROO_CORTEX_EDGEBITS 30 +#endif +#ifndef CUCKAROO_CORTEX_PROOFSIZE +// the next most important parameter is the (even) length +// of the cycle to be found. a minimum of 12 is recommended +#define CUCKAROO_CORTEX_PROOFSIZE 42 +#endif + +#if CUCKAROO_CORTEX_EDGEBITS > 30 +typedef uint64_t cuckaroo_cortex_word_t; +#elif CUCKAROO_CORTEX_EDGEBITS > 14 +typedef cuckaroo_cortex_u32 cuckaroo_cortex_word_t; +#else // if CUCKAROO_CORTEX_EDGEBITS <= 14 +typedef uint16_t cuckaroo_cortex_word_t; +#endif + +// number of edges +#define CUCKAROO_CORTEX_NEDGES ((cuckaroo_cortex_word_t)1 << CUCKAROO_CORTEX_EDGEBITS) +// used to mask siphash output +#define CUCKAROO_CORTEX_EDGEMASK ((cuckaroo_cortex_word_t)CUCKAROO_CORTEX_NEDGES - 1) + +enum cuckaroo_cortex_verify_code { CUCKAROO_CORTEX_POW_OK, CUCKAROO_CORTEX_POW_HEADER_LENGTH, CUCKAROO_CORTEX_POW_TOO_BIG, CUCKAROO_CORTEX_POW_TOO_SMALL, CUCKAROO_CORTEX_POW_NON_MATCHING, CUCKAROO_CORTEX_POW_BRANCH, CUCKAROO_CORTEX_POW_DEAD_END, CUCKAROO_CORTEX_POW_SHORT_CYCLE}; +const char *cuckaroo_cortex_errstr[] = { "OK", "wrong header length", "edge too big", "edges not ascending", "endpoints don't match up", "branch in cycle", "cycle dead ends", "cycle too short"}; + +// fills buffer with CUCKAROO_CORTEX_EDGE_BLOCK_SIZE siphash outputs for block containing edge in cuckaroo graph +// return siphash output for given edge +cuckaroo_cortex_u64 cuckaroo_cortex_sipblock(siphash_keys &keys, const cuckaroo_cortex_word_t edge, cuckaroo_cortex_u64 *buf) +{ + siphash_state<> shs(keys); + cuckaroo_cortex_word_t edge0 = edge & ~CUCKAROO_CORTEX_EDGE_BLOCK_MASK; + for (cuckaroo_cortex_u32 i=0; i < CUCKAROO_CORTEX_EDGE_BLOCK_SIZE; i++) + { + shs.hash24(edge0 + i); + buf[i] = shs.xor_lanes(); + } + const cuckaroo_cortex_u64 last = buf[CUCKAROO_CORTEX_EDGE_BLOCK_MASK]; + for (cuckaroo_cortex_u32 i=0; i < CUCKAROO_CORTEX_EDGE_BLOCK_MASK; i++) + buf[i] ^= last; + return buf[edge & CUCKAROO_CORTEX_EDGE_BLOCK_MASK]; +} + + +// verify that edges are ascending and form a cycle in header-generated graph +int cuckaroo_cortex_verify(cuckaroo_cortex_word_t edges[CUCKAROO_CORTEX_PROOFSIZE], siphash_keys &keys) +{ + cuckaroo_cortex_word_t xor0 = 0, xor1 = 0; + cuckaroo_cortex_u64 sips[CUCKAROO_CORTEX_EDGE_BLOCK_SIZE]; + cuckaroo_cortex_word_t uvs[2*CUCKAROO_CORTEX_PROOFSIZE]; + + for (cuckaroo_cortex_u32 n = 0; n < CUCKAROO_CORTEX_PROOFSIZE; n++) + { + if (edges[n] > CUCKAROO_CORTEX_EDGEMASK) + return CUCKAROO_CORTEX_POW_TOO_BIG; + if (n && edges[n] <= edges[n-1]) + return CUCKAROO_CORTEX_POW_TOO_SMALL; + cuckaroo_cortex_u64 edge = cuckaroo_cortex_sipblock(keys, edges[n], sips); + xor0 ^= uvs[2*n ] = edge & CUCKAROO_CORTEX_EDGEMASK; + xor1 ^= uvs[2*n+1] = (edge >> 32) & CUCKAROO_CORTEX_EDGEMASK; + } + if (xor0 | xor1) // optional check for obviously bad proofs + return CUCKAROO_CORTEX_POW_NON_MATCHING; + cuckaroo_cortex_u32 n = 0, i = 0, j; + do // follow cycle + { + for (cuckaroo_cortex_u32 k = j = i; (k = (k+2) % (2*CUCKAROO_CORTEX_PROOFSIZE)) != i; ) + { + if (uvs[k] == uvs[i])// find other edge endpoint identical to one at i + { + if (j != i) // already found one before + return CUCKAROO_CORTEX_POW_BRANCH; + j = k; + } + } + // no matching endpoint + if (j == i) return CUCKAROO_CORTEX_POW_DEAD_END; + i = j^1; + n++; + } while (i != 0); // must cycle back to start or we would have found branch + return n == CUCKAROO_CORTEX_PROOFSIZE ? CUCKAROO_CORTEX_POW_OK : CUCKAROO_CORTEX_POW_SHORT_CYCLE; +} + + +// convenience function for extracting siphash keys from header +void cuckaroo_cortex_setheader(const char *header, const cuckaroo_cortex_u32 headerlen, siphash_keys *keys) +{ + char hdrkey[32]; + // SHA256((unsigned char *)header, headerlen, (unsigned char *)hdrkey); + blake2b((void *)hdrkey, sizeof(hdrkey), (const void *)header, headerlen, 0, 0); + keys->setkeys(hdrkey); +} +#endif diff --git a/src/Native/libcortexcuckoocycle/cuckoo/cuckoo.h b/src/Native/libcortexcuckoocycle/cuckoo/cuckoo.h new file mode 100644 index 0000000000..61bf18bb33 --- /dev/null +++ b/src/Native/libcortexcuckoocycle/cuckoo/cuckoo.h @@ -0,0 +1,107 @@ +// Cuckoo Cycle, a memory-hard proof-of-work +// Copyright (c) 2013-2017 John Tromp +#ifndef CUCKOO_CORTEX_H +#define CUCKOO_CORTEX_H + +#include // for types uint32_t,uint64_t +#include // for functions strlen, memset +#include "../crypto/blake2.h" +#include "../crypto/siphash.hpp" + +#ifdef SIPHASH_COMPAT +#include +#endif + +// save some keystrokes since i'm a lazy typer +typedef uint32_t cuckoo_cortex_u32; +typedef uint64_t cuckoo_cortex_u64; + +// proof-of-work parameters +#ifndef CUCKOO_CORTEX_EDGEBITS +// the main parameter is the 2-log of the graph size, +// which is the size in bits of the node identifiers +#define CUCKOO_CORTEX_EDGEBITS 30 +#endif +#ifndef CUCKOO_CORTEX_PROOFSIZE +// the next most important parameter is the (even) length +// of the cycle to be found. a minimum of 12 is recommended +#define CUCKOO_CORTEX_PROOFSIZE 42 +#endif + +#if CUCKOO_CORTEX_EDGEBITS > 32 +typedef cuckoo_cortex_u64 cuckoo_cortex_edge_t; +#else +typedef cuckoo_cortex_u32 cuckoo_cortex_edge_t; +#endif +#if CUCKOO_CORTEX_EDGEBITS > 31 +typedef cuckoo_cortex_u64 cuckoo_cortex_node_t; +#else +typedef cuckoo_cortex_u32 cuckoo_cortex_node_t; +#endif + +// number of edges +#define CUCKOO_CORTEX_NEDGES ((cuckoo_cortex_node_t)1 << CUCKOO_CORTEX_EDGEBITS) +// used to mask siphash output +#define CUCKOO_CORTEX_EDGEMASK ((cuckoo_cortex_edge_t)CUCKOO_CORTEX_NEDGES - 1) + +// generate edge endpoint in cuckoo graph without partition bit +cuckoo_cortex_node_t cuckoo_cortex_sipnode(siphash_keys *keys, cuckoo_cortex_edge_t edge, cuckoo_cortex_u32 uorv) { + return keys->siphash24(2*edge + uorv) & CUCKOO_CORTEX_EDGEMASK; +} + +enum cuckoo_cortex_verify_code { CUCKOO_CORTEX_POW_OK, CUCKOO_CORTEX_POW_HEADER_LENGTH, CUCKOO_CORTEX_POW_TOO_BIG, CUCKOO_CORTEX_POW_TOO_SMALL, CUCKOO_CORTEX_POW_NON_MATCHING, CUCKOO_CORTEX_POW_BRANCH, CUCKOO_CORTEX_POW_DEAD_END, CUCKOO_CORTEX_POW_SHORT_CYCLE}; +const char *cuckoo_cortex_errstr[] = { "OK", "wrong header length", "edge too big", "edges not ascending", "endpoints don't match up", "branch in cycle", "cycle dead ends", "cycle too short"}; + +// verify that edges are ascending and form a cycle in header-generated graph +int cuckoo_cortex_verify(cuckoo_cortex_edge_t edges[CUCKOO_CORTEX_PROOFSIZE], siphash_keys *keys) { + cuckoo_cortex_node_t uvs[2*CUCKOO_CORTEX_PROOFSIZE]; + cuckoo_cortex_node_t xor0 = 0, xor1 =0; + for (cuckoo_cortex_u32 n = 0; n < CUCKOO_CORTEX_PROOFSIZE; n++) { + if (edges[n] > CUCKOO_CORTEX_EDGEMASK) + return CUCKOO_CORTEX_POW_TOO_BIG; + if (n && edges[n] <= edges[n-1]) + return CUCKOO_CORTEX_POW_TOO_SMALL; + xor0 ^= uvs[2*n ] = cuckoo_cortex_sipnode(keys, edges[n], 0); + xor1 ^= uvs[2*n+1] = cuckoo_cortex_sipnode(keys, edges[n], 1); + } + if (xor0|xor1) // optional check for obviously bad proofs + return CUCKOO_CORTEX_POW_NON_MATCHING; + cuckoo_cortex_u32 n = 0, i = 0, j; + do { // follow cycle + for (cuckoo_cortex_u32 k = j = i; (k = (k+2) % (2*CUCKOO_CORTEX_PROOFSIZE)) != i; ) { + if (uvs[k] == uvs[i]) { // find other edge endpoint identical to one at i + if (j != i) // already found one before + return CUCKOO_CORTEX_POW_BRANCH; + j = k; + } + } + if (j == i) return CUCKOO_CORTEX_POW_DEAD_END; // no matching endpoint + i = j^1; + n++; + } while (i != 0); // must cycle back to start or we would have found branch + return n == CUCKOO_CORTEX_PROOFSIZE ? CUCKOO_CORTEX_POW_OK : CUCKOO_CORTEX_POW_SHORT_CYCLE; +} + +// convenience function for extracting siphash keys from header +void cuckoo_cortex_setheader(const char *header, const cuckoo_cortex_u32 headerlen, siphash_keys *keys) { + char hdrkey[32]; + // SHA256((unsigned char *)header, headerlen, (unsigned char *)hdrkey); + blake2b((void *)hdrkey, sizeof(hdrkey), (const void *)header, headerlen, 0, 0); +#ifdef SIPHASH_COMPAT + cuckoo_cortex_u64 *k = (cuckoo_cortex_u64 *)hdrkey; + cuckoo_cortex_u64 k0 = k[0]; + cuckoo_cortex_u64 k1 = k[1]; + //printf("k0 k1 %lx %lx\n", k0, k1); + k[0] = k0 ^ 0x736f6d6570736575ULL; + k[1] = k1 ^ 0x646f72616e646f6dULL; + k[2] = k0 ^ 0x6c7967656e657261ULL; + k[3] = k1 ^ 0x7465646279746573ULL; +#endif + keys->setkeys(hdrkey); +} + +// edge endpoint in cuckoo graph with partition bit +cuckoo_cortex_edge_t cuckoo_cortex_sipnode_(siphash_keys *keys, cuckoo_cortex_edge_t edge, cuckoo_cortex_u32 uorv) { + return cuckoo_cortex_sipnode(keys, edge, uorv) << 1 | uorv; +} +#endif diff --git a/src/Native/libevrprogpow/dllmain.cpp b/src/Native/libcortexcuckoocycle/dllmain.cpp similarity index 100% rename from src/Native/libevrprogpow/dllmain.cpp rename to src/Native/libcortexcuckoocycle/dllmain.cpp diff --git a/src/Native/libsccpow/exports.cpp b/src/Native/libcortexcuckoocycle/exports.cpp similarity index 79% rename from src/Native/libsccpow/exports.cpp rename to src/Native/libcortexcuckoocycle/exports.cpp index 2004b4f482..2caa23b924 100644 --- a/src/Native/libsccpow/exports.cpp +++ b/src/Native/libcortexcuckoocycle/exports.cpp @@ -14,3 +14,16 @@ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMA 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. */ + +#include "cortexcuckoocycle.hpp" + +#ifdef _WIN32 +#define MODULE_API __declspec(dllexport) +#else +#define MODULE_API +#endif + +extern "C" MODULE_API int32_t cortexcuckoocycle_export(const char *header, int headerLen, const char *solution) +{ + return cortexcuckoocycle(header, headerLen, solution); +} \ No newline at end of file diff --git a/src/Native/libevrprogpow/libevrprogpow.sln b/src/Native/libcortexcuckoocycle/libcortexcuckoocycle.sln similarity index 54% rename from src/Native/libevrprogpow/libevrprogpow.sln rename to src/Native/libcortexcuckoocycle/libcortexcuckoocycle.sln index 27cf444d90..929d7da4f4 100644 --- a/src/Native/libevrprogpow/libevrprogpow.sln +++ b/src/Native/libcortexcuckoocycle/libcortexcuckoocycle.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31229.75 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libethhash", "libevrprogpow.vcxproj", "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmultihash", "libcortexcuckoocycle.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}.Debug|x64.ActiveCfg = Debug|x64 - {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}.Debug|x64.Build.0 = Debug|x64 - {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}.Debug|x86.ActiveCfg = Debug|Win32 - {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}.Debug|x86.Build.0 = Debug|Win32 - {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}.Release|x64.ActiveCfg = Release|x64 - {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}.Release|x64.Build.0 = Release|x64 - {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}.Release|x86.ActiveCfg = Release|Win32 - {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}.Release|x86.Build.0 = Release|Win32 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Debug|x64.ActiveCfg = Debug|x64 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Debug|x64.Build.0 = Debug|x64 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Debug|x86.ActiveCfg = Debug|Win32 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Debug|x86.Build.0 = Debug|Win32 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Release|x64.ActiveCfg = Release|x64 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Release|x64.Build.0 = Release|x64 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Release|x86.ActiveCfg = Release|Win32 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Native/libmeraki/libmeraki.vcxproj b/src/Native/libcortexcuckoocycle/libcortexcuckoocycle.vcxproj similarity index 89% rename from src/Native/libmeraki/libmeraki.vcxproj rename to src/Native/libcortexcuckoocycle/libcortexcuckoocycle.vcxproj index cd065d5629..c38a4f5cf0 100644 --- a/src/Native/libmeraki/libmeraki.vcxproj +++ b/src/Native/libcortexcuckoocycle/libcortexcuckoocycle.vcxproj @@ -24,7 +24,7 @@ Win32Proj netmultihashnative 10.0 - libmeraki + libcortexcuckoocycle @@ -168,33 +168,22 @@ - - - - - - - - - - - - - - + + + + + + + - + + + - - - - - - - + diff --git a/src/Native/libevrprogpow/stdafx.cpp b/src/Native/libcortexcuckoocycle/stdafx.cpp similarity index 100% rename from src/Native/libevrprogpow/stdafx.cpp rename to src/Native/libcortexcuckoocycle/stdafx.cpp diff --git a/src/Native/libevrprogpow/stdafx.h b/src/Native/libcortexcuckoocycle/stdafx.h similarity index 100% rename from src/Native/libevrprogpow/stdafx.h rename to src/Native/libcortexcuckoocycle/stdafx.h diff --git a/src/Native/libphihash/stdint.h b/src/Native/libcortexcuckoocycle/stdint.h similarity index 100% rename from src/Native/libphihash/stdint.h rename to src/Native/libcortexcuckoocycle/stdint.h diff --git a/src/Native/libevrprogpow/targetver.h b/src/Native/libcortexcuckoocycle/targetver.h similarity index 100% rename from src/Native/libevrprogpow/targetver.h rename to src/Native/libcortexcuckoocycle/targetver.h diff --git a/src/Native/libcryptonight/Makefile b/src/Native/libcryptonight/Makefile index 6e4ac8450f..c6db0f830e 100644 --- a/src/Native/libcryptonight/Makefile +++ b/src/Native/libcryptonight/Makefile @@ -63,11 +63,10 @@ OBJECTS = exports.o \ xmrig/crypto/ghostrider/sph_skein.o \ xmrig/crypto/ghostrider/sph_whirlpool.o \ xmrig-override/crypto/ghostrider/ghostrider.o \ - xmrig-override/crypto/mike/mike.o \ + xmrig-override/crypto/mike/mike.o \ \ - xmrig/3rdparty/libethash/keccakf800.o \ - \ - xmrig-override/crypto/flex/flex.o \ + xmrig/3rdparty/libethash/keccakf800.o + all: $(TARGET) diff --git a/src/Native/libcryptonight/exports.cpp b/src/Native/libcryptonight/exports.cpp index aeec7754dc..4f9dd3f08f 100644 --- a/src/Native/libcryptonight/exports.cpp +++ b/src/Native/libcryptonight/exports.cpp @@ -29,7 +29,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "crypto/kawpow/KPHash.h" #include "3rdparty/libethash/ethash.h" #include "crypto/ghostrider/ghostrider.h" -#include "crypto/flex/flex.h" #include "crypto/mike/mike.h" #include "crypto/common/portable/mm_malloc.h" @@ -73,10 +72,6 @@ void ghostrider(const uint8_t* data, size_t size, uint8_t * output, cryptonight_ xmrig::ghostrider::hash(data, size, output, ctx, nullptr); } -void flex(const unsigned char* data, long unsigned int size, unsigned char* output, cryptonight_ctx** ctx, long unsigned int) { - flex_hash((const char*)data, (char*)output, ctx); -} - void mike(const uint8_t* data, size_t size, uint8_t* output, cryptonight_ctx** ctx, uint64_t) { xmrig::mike::hash(data, size, output, ctx, nullptr); } @@ -97,8 +92,7 @@ static xmrig::cn_hash_fun get_cn_fn(const int algo) { case xmrig::Algorithm::CN_DOUBLE: return FNA(CN_DOUBLE); case xmrig::Algorithm::CN_CCX: return FNA(CN_CCX); case xmrig::Algorithm::GHOSTRIDER_RTM: return ghostrider; - case xmrig::Algorithm::FLEX_KCN: return flex; - case xmrig::Algorithm::GHOSTRIDER_MIKE: return mike; + case xmrig::Algorithm::GHOSTRIDER_MIKE: return mike; default: return FN(CN_R); } } diff --git a/src/Native/libcryptonight/xmrig-override/base/crypto/Algorithm.h b/src/Native/libcryptonight/xmrig-override/base/crypto/Algorithm.h index 9bc0d6ebec..8bde91f98f 100644 --- a/src/Native/libcryptonight/xmrig-override/base/crypto/Algorithm.h +++ b/src/Native/libcryptonight/xmrig-override/base/crypto/Algorithm.h @@ -8,6 +8,7 @@ * Copyright 2018 Lee Clagett * Copyright 2018-2019 SChernykh * Copyright 2016-2019 XMRig , + * Copyright 2024 FortuneBlock * * 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 @@ -84,8 +85,7 @@ class Algorithm CN_GR_4 = 0x63120104, // "cn/turtle" GhostRider CN_GR_5 = 0x63120105, // "cn/turtle-lite" GhostRider GHOSTRIDER_RTM = 0x6c150000, // "ghostrider" GhostRider - GHOSTRIDER_MIKE = 0x6c15006d, // "mike" Mike - FLEX_KCN = 0x6c150001, // "flex" Flex + GHOSTRIDER_MIKE = 0x6c15006d, // "mike" Mike RX_0 = 0x72151200, // "rx/0" RandomX (reference configuration). RX_WOW = 0x72141177, // "rx/wow" RandomWOW (Wownero). RX_ARQ = 0x72121061, // "rx/arq" RandomARQ (Arqma). diff --git a/src/Native/libcryptonight/xmrig-override/crypto/flex/flex.h b/src/Native/libcryptonight/xmrig-override/crypto/flex/flex.h deleted file mode 100644 index 402ead6614..0000000000 --- a/src/Native/libcryptonight/xmrig-override/crypto/flex/flex.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -struct cryptonight_ctx; -void flex_hash(const char* input, char* output, cryptonight_ctx** ctx); diff --git a/src/Native/libcryptonight/xmrig-override/crypto/mike/mike.cpp b/src/Native/libcryptonight/xmrig-override/crypto/mike/mike.cpp index 1e9416820b..052d778669 100644 --- a/src/Native/libcryptonight/xmrig-override/crypto/mike/mike.cpp +++ b/src/Native/libcryptonight/xmrig-override/crypto/mike/mike.cpp @@ -834,4 +834,4 @@ void hash(const uint8_t* data, size_t size, uint8_t* output, cryptonight_ctx** c } // namespace mike -} // namespace xmrig \ No newline at end of file +} // namespace xmrig diff --git a/src/Native/libcryptonight/xmrig-override/crypto/mike/mike.h b/src/Native/libcryptonight/xmrig-override/crypto/mike/mike.h index 35d6204c8b..594d3212c9 100644 --- a/src/Native/libcryptonight/xmrig-override/crypto/mike/mike.h +++ b/src/Native/libcryptonight/xmrig-override/crypto/mike/mike.h @@ -49,4 +49,4 @@ void hash(const uint8_t* data, size_t size, uint8_t* output, cryptonight_ctx** c } // namespace xmrig -#endif // XMRIG_MIKE_HASH_H \ No newline at end of file +#endif // XMRIG_MIKE_HASH_H diff --git a/src/Native/libcryptonight/xmrig/crypto/cn/CnAlgo.h b/src/Native/libcryptonight/xmrig/crypto/cn/CnAlgo.h index 43f1f4fbc0..26e6e4e001 100644 --- a/src/Native/libcryptonight/xmrig/crypto/cn/CnAlgo.h +++ b/src/Native/libcryptonight/xmrig/crypto/cn/CnAlgo.h @@ -1,6 +1,7 @@ /* XMRig * Copyright (c) 2018-2021 SChernykh * Copyright (c) 2016-2021 XMRig , + * Copyright 2024 FortuneBlock * * 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 diff --git a/src/Native/libcryptonight/xmrig/crypto/cn/CnHash.cpp b/src/Native/libcryptonight/xmrig/crypto/cn/CnHash.cpp index a0be90e153..6c49adffb3 100644 --- a/src/Native/libcryptonight/xmrig/crypto/cn/CnHash.cpp +++ b/src/Native/libcryptonight/xmrig/crypto/cn/CnHash.cpp @@ -2,6 +2,7 @@ * Copyright 2018 Lee Clagett * Copyright 2018-2021 SChernykh * Copyright 2016-2021 XMRig , + * Copyright 2024 FortuneBlock * * 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 diff --git a/src/Native/libcryptonight/xmrig/crypto/cn/CryptoNight_test.h b/src/Native/libcryptonight/xmrig/crypto/cn/CryptoNight_test.h index 3a09bc95b0..9610b4ff4f 100644 --- a/src/Native/libcryptonight/xmrig/crypto/cn/CryptoNight_test.h +++ b/src/Native/libcryptonight/xmrig/crypto/cn/CryptoNight_test.h @@ -8,6 +8,7 @@ * Copyright 2018 Lee Clagett * Copyright 2018-2020 SChernykh * Copyright 2016-2020 XMRig , + * Copyright 2024 FortuneBlock * * 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 @@ -488,6 +489,7 @@ const static uint8_t test_output_gr[256] = { }; #endif + #ifdef XMRIG_ALGO_MIKE // "Mike" const static uint8_t test_output_mike[256] = { @@ -509,8 +511,9 @@ const static uint8_t test_output_mike[256] = { 0x73, 0x92, 0xee, 0x64, 0xa6, 0x44, 0xac, 0xd4, 0x33, 0xb8, 0x3b, 0x84, 0x42, 0x7e, 0x9a, 0x80, 0xf0, 0xa8, 0x71, 0xf0, 0x81, 0xc4, 0xc1, 0x52, 0xff, 0x27, 0x4e, 0x7, 0xf0, 0x70 }; - #endif + + } // namespace xmrig diff --git a/src/Native/libcryptonight/xmrig/crypto/cn/CryptoNight_x86.h b/src/Native/libcryptonight/xmrig/crypto/cn/CryptoNight_x86.h index 76ec6239c4..c0063a87d5 100644 --- a/src/Native/libcryptonight/xmrig/crypto/cn/CryptoNight_x86.h +++ b/src/Native/libcryptonight/xmrig/crypto/cn/CryptoNight_x86.h @@ -82,15 +82,10 @@ static inline void do_skein_hash(const uint8_t *input, size_t len, uint8_t *outp } -static inline void do_flex_skein_hash(const uint8_t* input, size_t len, uint8_t* output) { - int r = skein_hash(512, input, 8 * len, (uint8_t*)output); - assert(SKEIN_SUCCESS == r); -} - void (* const extra_hashes[4])(const uint8_t *, size_t, uint8_t *) = {do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash}; -void (* const extra_hashes_flex[3])(const uint8_t *, size_t, uint8_t *) = {do_blake_hash, do_groestl_hash, do_flex_skein_hash}; -#if (defined(__i386__) || defined(_M_IX86)) && !(defined(__clang__) && defined(__clang_major__) && (__clang_major__ >= 15)) + +#if defined(__i386__) || defined(_M_IX86) static inline int64_t _mm_cvtsi128_si64(__m128i a) { return ((uint64_t)(uint32_t)_mm_cvtsi128_si32(a) | ((uint64_t)(uint32_t)_mm_cvtsi128_si32(_mm_srli_si128(a, 4)) << 32)); @@ -831,11 +826,7 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si cn_implode_scratchpad(ctx[0]); keccakf(h0, 24); - - if (height == 101) // Flex algo ugly hack - extra_hashes_flex[ctx[0]->state[0] & 2](ctx[0]->state, 200, output); - else - extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); + extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); } @@ -1083,11 +1074,7 @@ inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_ cn_implode_scratchpad(ctx[0]); keccakf(reinterpret_cast(ctx[0]->state), 24); - - if (height == 101) // Flex algo ugly hack - extra_hashes_flex[ctx[0]->state[0] & 2](ctx[0]->state, 200, output); - else - extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); + extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); } diff --git a/src/Native/libcryptonight/xmrig/crypto/ghostrider/sph_keccak.c b/src/Native/libcryptonight/xmrig/crypto/ghostrider/sph_keccak.c index c18220a037..539ec02c91 100644 --- a/src/Native/libcryptonight/xmrig/crypto/ghostrider/sph_keccak.c +++ b/src/Native/libcryptonight/xmrig/crypto/ghostrider/sph_keccak.c @@ -5,7 +5,7 @@ * ==========================(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 @@ -13,10 +13,10 @@ * 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. @@ -30,15 +30,17 @@ * @author Thomas Pornin */ +#include "sph_keccak.h" #include #include -#include "sph_keccak.h" - #ifdef __cplusplus -extern "C"{ +extern "C" { #endif +// Taken from keccak-gate.c +int hard_coded_eb = 1; + /* * Parameters: * @@ -46,7 +48,7 @@ extern "C"{ * SPH_KECCAK_UNROLL number of loops to unroll (0/undef for full unroll) * SPH_KECCAK_INTERLEAVE use bit-interleaving (32-bit type only) * SPH_KECCAK_NOCOPY do not copy the state into local variables - * + * * If there is no usable 64-bit type, the code automatically switches * back to the 32-bit implementation. * @@ -85,23 +87,23 @@ extern "C"{ */ #if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_KECCAK -#define SPH_SMALL_FOOTPRINT_KECCAK 1 +#define SPH_SMALL_FOOTPRINT_KECCAK 1 #endif /* * By default, we select the 64-bit implementation if a 64-bit type * is available, unless a 32-bit x86 is detected. */ -#if !defined SPH_KECCAK_64 && SPH_64 \ - && !(defined __i386__ || SPH_I386_GCC || SPH_I386_MSVC) -#define SPH_KECCAK_64 1 +#if !defined SPH_KECCAK_64 && SPH_64 && \ + !(defined __i386__ || SPH_I386_GCC || SPH_I386_MSVC) +#define SPH_KECCAK_64 1 #endif /* * If using a 32-bit implementation, we prefer to interleave. */ #if !SPH_KECCAK_64 && !defined SPH_KECCAK_INTERLEAVE -#define SPH_KECCAK_INTERLEAVE 1 +#define SPH_KECCAK_INTERLEAVE 1 #endif /* @@ -109,9 +111,9 @@ extern "C"{ */ #ifndef SPH_KECCAK_UNROLL #if SPH_SMALL_FOOTPRINT_KECCAK -#define SPH_KECCAK_UNROLL 2 +#define SPH_KECCAK_UNROLL 2 #else -#define SPH_KECCAK_UNROLL 8 +#define SPH_KECCAK_UNROLL 8 #endif #endif @@ -121,340 +123,371 @@ extern "C"{ */ #ifndef SPH_KECCAK_NOCOPY #if defined __i386__ || defined __x86_64 || SPH_I386_MSVC || SPH_I386_GCC -#define SPH_KECCAK_NOCOPY 1 +#define SPH_KECCAK_NOCOPY 1 #else -#define SPH_KECCAK_NOCOPY 0 +#define SPH_KECCAK_NOCOPY 0 #endif #endif #ifdef _MSC_VER -#pragma warning (disable: 4146) +#pragma warning(disable : 4146) #endif #if SPH_KECCAK_64 static const sph_u64 RC[] = { - SPH_C64(0x0000000000000001), SPH_C64(0x0000000000008082), - SPH_C64(0x800000000000808A), SPH_C64(0x8000000080008000), - SPH_C64(0x000000000000808B), SPH_C64(0x0000000080000001), - SPH_C64(0x8000000080008081), SPH_C64(0x8000000000008009), - SPH_C64(0x000000000000008A), SPH_C64(0x0000000000000088), - SPH_C64(0x0000000080008009), SPH_C64(0x000000008000000A), - SPH_C64(0x000000008000808B), SPH_C64(0x800000000000008B), - SPH_C64(0x8000000000008089), SPH_C64(0x8000000000008003), - SPH_C64(0x8000000000008002), SPH_C64(0x8000000000000080), - SPH_C64(0x000000000000800A), SPH_C64(0x800000008000000A), - SPH_C64(0x8000000080008081), SPH_C64(0x8000000000008080), - SPH_C64(0x0000000080000001), SPH_C64(0x8000000080008008) -}; + SPH_C64(0x0000000000000001), SPH_C64(0x0000000000008082), + SPH_C64(0x800000000000808A), SPH_C64(0x8000000080008000), + SPH_C64(0x000000000000808B), SPH_C64(0x0000000080000001), + SPH_C64(0x8000000080008081), SPH_C64(0x8000000000008009), + SPH_C64(0x000000000000008A), SPH_C64(0x0000000000000088), + SPH_C64(0x0000000080008009), SPH_C64(0x000000008000000A), + SPH_C64(0x000000008000808B), SPH_C64(0x800000000000008B), + SPH_C64(0x8000000000008089), SPH_C64(0x8000000000008003), + SPH_C64(0x8000000000008002), SPH_C64(0x8000000000000080), + SPH_C64(0x000000000000800A), SPH_C64(0x800000008000000A), + SPH_C64(0x8000000080008081), SPH_C64(0x8000000000008080), + SPH_C64(0x0000000080000001), SPH_C64(0x8000000080008008)}; #if SPH_KECCAK_NOCOPY -#define a00 (kc->u.wide[ 0]) -#define a10 (kc->u.wide[ 1]) -#define a20 (kc->u.wide[ 2]) -#define a30 (kc->u.wide[ 3]) -#define a40 (kc->u.wide[ 4]) -#define a01 (kc->u.wide[ 5]) -#define a11 (kc->u.wide[ 6]) -#define a21 (kc->u.wide[ 7]) -#define a31 (kc->u.wide[ 8]) -#define a41 (kc->u.wide[ 9]) -#define a02 (kc->u.wide[10]) -#define a12 (kc->u.wide[11]) -#define a22 (kc->u.wide[12]) -#define a32 (kc->u.wide[13]) -#define a42 (kc->u.wide[14]) -#define a03 (kc->u.wide[15]) -#define a13 (kc->u.wide[16]) -#define a23 (kc->u.wide[17]) -#define a33 (kc->u.wide[18]) -#define a43 (kc->u.wide[19]) -#define a04 (kc->u.wide[20]) -#define a14 (kc->u.wide[21]) -#define a24 (kc->u.wide[22]) -#define a34 (kc->u.wide[23]) -#define a44 (kc->u.wide[24]) +#define a00 (kc->u.wide[0]) +#define a10 (kc->u.wide[1]) +#define a20 (kc->u.wide[2]) +#define a30 (kc->u.wide[3]) +#define a40 (kc->u.wide[4]) +#define a01 (kc->u.wide[5]) +#define a11 (kc->u.wide[6]) +#define a21 (kc->u.wide[7]) +#define a31 (kc->u.wide[8]) +#define a41 (kc->u.wide[9]) +#define a02 (kc->u.wide[10]) +#define a12 (kc->u.wide[11]) +#define a22 (kc->u.wide[12]) +#define a32 (kc->u.wide[13]) +#define a42 (kc->u.wide[14]) +#define a03 (kc->u.wide[15]) +#define a13 (kc->u.wide[16]) +#define a23 (kc->u.wide[17]) +#define a33 (kc->u.wide[18]) +#define a43 (kc->u.wide[19]) +#define a04 (kc->u.wide[20]) +#define a14 (kc->u.wide[21]) +#define a24 (kc->u.wide[22]) +#define a34 (kc->u.wide[23]) +#define a44 (kc->u.wide[24]) #define DECL_STATE #define READ_STATE(sc) #define WRITE_STATE(sc) -#define INPUT_BUF(size) do { \ - size_t j; \ - for (j = 0; j < (size); j += 8) { \ - kc->u.wide[j >> 3] ^= sph_dec64le_aligned(buf + j); \ - } \ - } while (0) +#define INPUT_BUF(size) \ + do { \ + size_t j; \ + for (j = 0; j < (size); j += 8) { \ + kc->u.wide[j >> 3] ^= sph_dec64le_aligned(buf + j); \ + } \ + } while (0) -#define INPUT_BUF144 INPUT_BUF(144) -#define INPUT_BUF136 INPUT_BUF(136) -#define INPUT_BUF104 INPUT_BUF(104) -#define INPUT_BUF72 INPUT_BUF(72) +#define INPUT_BUF144 INPUT_BUF(144) +#define INPUT_BUF136 INPUT_BUF(136) +#define INPUT_BUF104 INPUT_BUF(104) +#define INPUT_BUF72 INPUT_BUF(72) #else -#define DECL_STATE \ - sph_u64 a00, a01, a02, a03, a04; \ - sph_u64 a10, a11, a12, a13, a14; \ - sph_u64 a20, a21, a22, a23, a24; \ - sph_u64 a30, a31, a32, a33, a34; \ - sph_u64 a40, a41, a42, a43, a44; - -#define READ_STATE(state) do { \ - a00 = (state)->u.wide[ 0]; \ - a10 = (state)->u.wide[ 1]; \ - a20 = (state)->u.wide[ 2]; \ - a30 = (state)->u.wide[ 3]; \ - a40 = (state)->u.wide[ 4]; \ - a01 = (state)->u.wide[ 5]; \ - a11 = (state)->u.wide[ 6]; \ - a21 = (state)->u.wide[ 7]; \ - a31 = (state)->u.wide[ 8]; \ - a41 = (state)->u.wide[ 9]; \ - a02 = (state)->u.wide[10]; \ - a12 = (state)->u.wide[11]; \ - a22 = (state)->u.wide[12]; \ - a32 = (state)->u.wide[13]; \ - a42 = (state)->u.wide[14]; \ - a03 = (state)->u.wide[15]; \ - a13 = (state)->u.wide[16]; \ - a23 = (state)->u.wide[17]; \ - a33 = (state)->u.wide[18]; \ - a43 = (state)->u.wide[19]; \ - a04 = (state)->u.wide[20]; \ - a14 = (state)->u.wide[21]; \ - a24 = (state)->u.wide[22]; \ - a34 = (state)->u.wide[23]; \ - a44 = (state)->u.wide[24]; \ - } while (0) - -#define WRITE_STATE(state) do { \ - (state)->u.wide[ 0] = a00; \ - (state)->u.wide[ 1] = a10; \ - (state)->u.wide[ 2] = a20; \ - (state)->u.wide[ 3] = a30; \ - (state)->u.wide[ 4] = a40; \ - (state)->u.wide[ 5] = a01; \ - (state)->u.wide[ 6] = a11; \ - (state)->u.wide[ 7] = a21; \ - (state)->u.wide[ 8] = a31; \ - (state)->u.wide[ 9] = a41; \ - (state)->u.wide[10] = a02; \ - (state)->u.wide[11] = a12; \ - (state)->u.wide[12] = a22; \ - (state)->u.wide[13] = a32; \ - (state)->u.wide[14] = a42; \ - (state)->u.wide[15] = a03; \ - (state)->u.wide[16] = a13; \ - (state)->u.wide[17] = a23; \ - (state)->u.wide[18] = a33; \ - (state)->u.wide[19] = a43; \ - (state)->u.wide[20] = a04; \ - (state)->u.wide[21] = a14; \ - (state)->u.wide[22] = a24; \ - (state)->u.wide[23] = a34; \ - (state)->u.wide[24] = a44; \ - } while (0) - -#define INPUT_BUF144 do { \ - a00 ^= sph_dec64le_aligned(buf + 0); \ - a10 ^= sph_dec64le_aligned(buf + 8); \ - a20 ^= sph_dec64le_aligned(buf + 16); \ - a30 ^= sph_dec64le_aligned(buf + 24); \ - a40 ^= sph_dec64le_aligned(buf + 32); \ - a01 ^= sph_dec64le_aligned(buf + 40); \ - a11 ^= sph_dec64le_aligned(buf + 48); \ - a21 ^= sph_dec64le_aligned(buf + 56); \ - a31 ^= sph_dec64le_aligned(buf + 64); \ - a41 ^= sph_dec64le_aligned(buf + 72); \ - a02 ^= sph_dec64le_aligned(buf + 80); \ - a12 ^= sph_dec64le_aligned(buf + 88); \ - a22 ^= sph_dec64le_aligned(buf + 96); \ - a32 ^= sph_dec64le_aligned(buf + 104); \ - a42 ^= sph_dec64le_aligned(buf + 112); \ - a03 ^= sph_dec64le_aligned(buf + 120); \ - a13 ^= sph_dec64le_aligned(buf + 128); \ - a23 ^= sph_dec64le_aligned(buf + 136); \ - } while (0) - -#define INPUT_BUF136 do { \ - a00 ^= sph_dec64le_aligned(buf + 0); \ - a10 ^= sph_dec64le_aligned(buf + 8); \ - a20 ^= sph_dec64le_aligned(buf + 16); \ - a30 ^= sph_dec64le_aligned(buf + 24); \ - a40 ^= sph_dec64le_aligned(buf + 32); \ - a01 ^= sph_dec64le_aligned(buf + 40); \ - a11 ^= sph_dec64le_aligned(buf + 48); \ - a21 ^= sph_dec64le_aligned(buf + 56); \ - a31 ^= sph_dec64le_aligned(buf + 64); \ - a41 ^= sph_dec64le_aligned(buf + 72); \ - a02 ^= sph_dec64le_aligned(buf + 80); \ - a12 ^= sph_dec64le_aligned(buf + 88); \ - a22 ^= sph_dec64le_aligned(buf + 96); \ - a32 ^= sph_dec64le_aligned(buf + 104); \ - a42 ^= sph_dec64le_aligned(buf + 112); \ - a03 ^= sph_dec64le_aligned(buf + 120); \ - a13 ^= sph_dec64le_aligned(buf + 128); \ - } while (0) - -#define INPUT_BUF104 do { \ - a00 ^= sph_dec64le_aligned(buf + 0); \ - a10 ^= sph_dec64le_aligned(buf + 8); \ - a20 ^= sph_dec64le_aligned(buf + 16); \ - a30 ^= sph_dec64le_aligned(buf + 24); \ - a40 ^= sph_dec64le_aligned(buf + 32); \ - a01 ^= sph_dec64le_aligned(buf + 40); \ - a11 ^= sph_dec64le_aligned(buf + 48); \ - a21 ^= sph_dec64le_aligned(buf + 56); \ - a31 ^= sph_dec64le_aligned(buf + 64); \ - a41 ^= sph_dec64le_aligned(buf + 72); \ - a02 ^= sph_dec64le_aligned(buf + 80); \ - a12 ^= sph_dec64le_aligned(buf + 88); \ - a22 ^= sph_dec64le_aligned(buf + 96); \ - } while (0) - -#define INPUT_BUF72 do { \ - a00 ^= sph_dec64le_aligned(buf + 0); \ - a10 ^= sph_dec64le_aligned(buf + 8); \ - a20 ^= sph_dec64le_aligned(buf + 16); \ - a30 ^= sph_dec64le_aligned(buf + 24); \ - a40 ^= sph_dec64le_aligned(buf + 32); \ - a01 ^= sph_dec64le_aligned(buf + 40); \ - a11 ^= sph_dec64le_aligned(buf + 48); \ - a21 ^= sph_dec64le_aligned(buf + 56); \ - a31 ^= sph_dec64le_aligned(buf + 64); \ - } while (0) - -#define INPUT_BUF(lim) do { \ - a00 ^= sph_dec64le_aligned(buf + 0); \ - a10 ^= sph_dec64le_aligned(buf + 8); \ - a20 ^= sph_dec64le_aligned(buf + 16); \ - a30 ^= sph_dec64le_aligned(buf + 24); \ - a40 ^= sph_dec64le_aligned(buf + 32); \ - a01 ^= sph_dec64le_aligned(buf + 40); \ - a11 ^= sph_dec64le_aligned(buf + 48); \ - a21 ^= sph_dec64le_aligned(buf + 56); \ - a31 ^= sph_dec64le_aligned(buf + 64); \ - if ((lim) == 72) \ - break; \ - a41 ^= sph_dec64le_aligned(buf + 72); \ - a02 ^= sph_dec64le_aligned(buf + 80); \ - a12 ^= sph_dec64le_aligned(buf + 88); \ - a22 ^= sph_dec64le_aligned(buf + 96); \ - if ((lim) == 104) \ - break; \ - a32 ^= sph_dec64le_aligned(buf + 104); \ - a42 ^= sph_dec64le_aligned(buf + 112); \ - a03 ^= sph_dec64le_aligned(buf + 120); \ - a13 ^= sph_dec64le_aligned(buf + 128); \ - if ((lim) == 136) \ - break; \ - a23 ^= sph_dec64le_aligned(buf + 136); \ - } while (0) +#define DECL_STATE \ + sph_u64 a00, a01, a02, a03, a04; \ + sph_u64 a10, a11, a12, a13, a14; \ + sph_u64 a20, a21, a22, a23, a24; \ + sph_u64 a30, a31, a32, a33, a34; \ + sph_u64 a40, a41, a42, a43, a44; + +#define READ_STATE(state) \ + do { \ + a00 = (state)->u.wide[0]; \ + a10 = (state)->u.wide[1]; \ + a20 = (state)->u.wide[2]; \ + a30 = (state)->u.wide[3]; \ + a40 = (state)->u.wide[4]; \ + a01 = (state)->u.wide[5]; \ + a11 = (state)->u.wide[6]; \ + a21 = (state)->u.wide[7]; \ + a31 = (state)->u.wide[8]; \ + a41 = (state)->u.wide[9]; \ + a02 = (state)->u.wide[10]; \ + a12 = (state)->u.wide[11]; \ + a22 = (state)->u.wide[12]; \ + a32 = (state)->u.wide[13]; \ + a42 = (state)->u.wide[14]; \ + a03 = (state)->u.wide[15]; \ + a13 = (state)->u.wide[16]; \ + a23 = (state)->u.wide[17]; \ + a33 = (state)->u.wide[18]; \ + a43 = (state)->u.wide[19]; \ + a04 = (state)->u.wide[20]; \ + a14 = (state)->u.wide[21]; \ + a24 = (state)->u.wide[22]; \ + a34 = (state)->u.wide[23]; \ + a44 = (state)->u.wide[24]; \ + } while (0) + +#define WRITE_STATE(state) \ + do { \ + (state)->u.wide[0] = a00; \ + (state)->u.wide[1] = a10; \ + (state)->u.wide[2] = a20; \ + (state)->u.wide[3] = a30; \ + (state)->u.wide[4] = a40; \ + (state)->u.wide[5] = a01; \ + (state)->u.wide[6] = a11; \ + (state)->u.wide[7] = a21; \ + (state)->u.wide[8] = a31; \ + (state)->u.wide[9] = a41; \ + (state)->u.wide[10] = a02; \ + (state)->u.wide[11] = a12; \ + (state)->u.wide[12] = a22; \ + (state)->u.wide[13] = a32; \ + (state)->u.wide[14] = a42; \ + (state)->u.wide[15] = a03; \ + (state)->u.wide[16] = a13; \ + (state)->u.wide[17] = a23; \ + (state)->u.wide[18] = a33; \ + (state)->u.wide[19] = a43; \ + (state)->u.wide[20] = a04; \ + (state)->u.wide[21] = a14; \ + (state)->u.wide[22] = a24; \ + (state)->u.wide[23] = a34; \ + (state)->u.wide[24] = a44; \ + } while (0) + +#define INPUT_BUF144 \ + do { \ + a00 ^= sph_dec64le_aligned(buf + 0); \ + a10 ^= sph_dec64le_aligned(buf + 8); \ + a20 ^= sph_dec64le_aligned(buf + 16); \ + a30 ^= sph_dec64le_aligned(buf + 24); \ + a40 ^= sph_dec64le_aligned(buf + 32); \ + a01 ^= sph_dec64le_aligned(buf + 40); \ + a11 ^= sph_dec64le_aligned(buf + 48); \ + a21 ^= sph_dec64le_aligned(buf + 56); \ + a31 ^= sph_dec64le_aligned(buf + 64); \ + a41 ^= sph_dec64le_aligned(buf + 72); \ + a02 ^= sph_dec64le_aligned(buf + 80); \ + a12 ^= sph_dec64le_aligned(buf + 88); \ + a22 ^= sph_dec64le_aligned(buf + 96); \ + a32 ^= sph_dec64le_aligned(buf + 104); \ + a42 ^= sph_dec64le_aligned(buf + 112); \ + a03 ^= sph_dec64le_aligned(buf + 120); \ + a13 ^= sph_dec64le_aligned(buf + 128); \ + a23 ^= sph_dec64le_aligned(buf + 136); \ + } while (0) + +#define INPUT_BUF136 \ + do { \ + a00 ^= sph_dec64le_aligned(buf + 0); \ + a10 ^= sph_dec64le_aligned(buf + 8); \ + a20 ^= sph_dec64le_aligned(buf + 16); \ + a30 ^= sph_dec64le_aligned(buf + 24); \ + a40 ^= sph_dec64le_aligned(buf + 32); \ + a01 ^= sph_dec64le_aligned(buf + 40); \ + a11 ^= sph_dec64le_aligned(buf + 48); \ + a21 ^= sph_dec64le_aligned(buf + 56); \ + a31 ^= sph_dec64le_aligned(buf + 64); \ + a41 ^= sph_dec64le_aligned(buf + 72); \ + a02 ^= sph_dec64le_aligned(buf + 80); \ + a12 ^= sph_dec64le_aligned(buf + 88); \ + a22 ^= sph_dec64le_aligned(buf + 96); \ + a32 ^= sph_dec64le_aligned(buf + 104); \ + a42 ^= sph_dec64le_aligned(buf + 112); \ + a03 ^= sph_dec64le_aligned(buf + 120); \ + a13 ^= sph_dec64le_aligned(buf + 128); \ + } while (0) + +#define INPUT_BUF104 \ + do { \ + a00 ^= sph_dec64le_aligned(buf + 0); \ + a10 ^= sph_dec64le_aligned(buf + 8); \ + a20 ^= sph_dec64le_aligned(buf + 16); \ + a30 ^= sph_dec64le_aligned(buf + 24); \ + a40 ^= sph_dec64le_aligned(buf + 32); \ + a01 ^= sph_dec64le_aligned(buf + 40); \ + a11 ^= sph_dec64le_aligned(buf + 48); \ + a21 ^= sph_dec64le_aligned(buf + 56); \ + a31 ^= sph_dec64le_aligned(buf + 64); \ + a41 ^= sph_dec64le_aligned(buf + 72); \ + a02 ^= sph_dec64le_aligned(buf + 80); \ + a12 ^= sph_dec64le_aligned(buf + 88); \ + a22 ^= sph_dec64le_aligned(buf + 96); \ + } while (0) + +#define INPUT_BUF72 \ + do { \ + a00 ^= sph_dec64le_aligned(buf + 0); \ + a10 ^= sph_dec64le_aligned(buf + 8); \ + a20 ^= sph_dec64le_aligned(buf + 16); \ + a30 ^= sph_dec64le_aligned(buf + 24); \ + a40 ^= sph_dec64le_aligned(buf + 32); \ + a01 ^= sph_dec64le_aligned(buf + 40); \ + a11 ^= sph_dec64le_aligned(buf + 48); \ + a21 ^= sph_dec64le_aligned(buf + 56); \ + a31 ^= sph_dec64le_aligned(buf + 64); \ + } while (0) + +#define INPUT_BUF(lim) \ + do { \ + a00 ^= sph_dec64le_aligned(buf + 0); \ + a10 ^= sph_dec64le_aligned(buf + 8); \ + a20 ^= sph_dec64le_aligned(buf + 16); \ + a30 ^= sph_dec64le_aligned(buf + 24); \ + a40 ^= sph_dec64le_aligned(buf + 32); \ + a01 ^= sph_dec64le_aligned(buf + 40); \ + a11 ^= sph_dec64le_aligned(buf + 48); \ + a21 ^= sph_dec64le_aligned(buf + 56); \ + a31 ^= sph_dec64le_aligned(buf + 64); \ + if ((lim) == 72) \ + break; \ + a41 ^= sph_dec64le_aligned(buf + 72); \ + a02 ^= sph_dec64le_aligned(buf + 80); \ + a12 ^= sph_dec64le_aligned(buf + 88); \ + a22 ^= sph_dec64le_aligned(buf + 96); \ + if ((lim) == 104) \ + break; \ + a32 ^= sph_dec64le_aligned(buf + 104); \ + a42 ^= sph_dec64le_aligned(buf + 112); \ + a03 ^= sph_dec64le_aligned(buf + 120); \ + a13 ^= sph_dec64le_aligned(buf + 128); \ + if ((lim) == 136) \ + break; \ + a23 ^= sph_dec64le_aligned(buf + 136); \ + } while (0) #endif -#define DECL64(x) sph_u64 x -#define MOV64(d, s) (d = s) -#define XOR64(d, a, b) (d = a ^ b) -#define AND64(d, a, b) (d = a & b) -#define OR64(d, a, b) (d = a | b) -#define NOT64(d, s) (d = SPH_T64(~s)) -#define ROL64(d, v, n) (d = SPH_ROTL64(v, n)) -#define XOR64_IOTA XOR64 +#define DECL64(x) sph_u64 x +#define MOV64(d, s) (d = s) +#define XOR64(d, a, b) (d = a ^ b) +#define AND64(d, a, b) (d = a & b) +#define OR64(d, a, b) (d = a | b) +#define NOT64(d, s) (d = SPH_T64(~s)) +#define ROL64(d, v, n) (d = SPH_ROTL64(v, n)) +#define XOR64_IOTA XOR64 #else static const struct { - sph_u32 high, low; + sph_u32 high, low; } RC[] = { #if SPH_KECCAK_INTERLEAVE - { SPH_C32(0x00000000), SPH_C32(0x00000001) }, - { SPH_C32(0x00000089), SPH_C32(0x00000000) }, - { SPH_C32(0x8000008B), SPH_C32(0x00000000) }, - { SPH_C32(0x80008080), SPH_C32(0x00000000) }, - { SPH_C32(0x0000008B), SPH_C32(0x00000001) }, - { SPH_C32(0x00008000), SPH_C32(0x00000001) }, - { SPH_C32(0x80008088), SPH_C32(0x00000001) }, - { SPH_C32(0x80000082), SPH_C32(0x00000001) }, - { SPH_C32(0x0000000B), SPH_C32(0x00000000) }, - { SPH_C32(0x0000000A), SPH_C32(0x00000000) }, - { SPH_C32(0x00008082), SPH_C32(0x00000001) }, - { SPH_C32(0x00008003), SPH_C32(0x00000000) }, - { SPH_C32(0x0000808B), SPH_C32(0x00000001) }, - { SPH_C32(0x8000000B), SPH_C32(0x00000001) }, - { SPH_C32(0x8000008A), SPH_C32(0x00000001) }, - { SPH_C32(0x80000081), SPH_C32(0x00000001) }, - { SPH_C32(0x80000081), SPH_C32(0x00000000) }, - { SPH_C32(0x80000008), SPH_C32(0x00000000) }, - { SPH_C32(0x00000083), SPH_C32(0x00000000) }, - { SPH_C32(0x80008003), SPH_C32(0x00000000) }, - { SPH_C32(0x80008088), SPH_C32(0x00000001) }, - { SPH_C32(0x80000088), SPH_C32(0x00000000) }, - { SPH_C32(0x00008000), SPH_C32(0x00000001) }, - { SPH_C32(0x80008082), SPH_C32(0x00000000) } + {SPH_C32(0x00000000), SPH_C32(0x00000001)}, + {SPH_C32(0x00000089), SPH_C32(0x00000000)}, + {SPH_C32(0x8000008B), SPH_C32(0x00000000)}, + {SPH_C32(0x80008080), SPH_C32(0x00000000)}, + {SPH_C32(0x0000008B), SPH_C32(0x00000001)}, + {SPH_C32(0x00008000), SPH_C32(0x00000001)}, + {SPH_C32(0x80008088), SPH_C32(0x00000001)}, + {SPH_C32(0x80000082), SPH_C32(0x00000001)}, + {SPH_C32(0x0000000B), SPH_C32(0x00000000)}, + {SPH_C32(0x0000000A), SPH_C32(0x00000000)}, + {SPH_C32(0x00008082), SPH_C32(0x00000001)}, + {SPH_C32(0x00008003), SPH_C32(0x00000000)}, + {SPH_C32(0x0000808B), SPH_C32(0x00000001)}, + {SPH_C32(0x8000000B), SPH_C32(0x00000001)}, + {SPH_C32(0x8000008A), SPH_C32(0x00000001)}, + {SPH_C32(0x80000081), SPH_C32(0x00000001)}, + {SPH_C32(0x80000081), SPH_C32(0x00000000)}, + {SPH_C32(0x80000008), SPH_C32(0x00000000)}, + {SPH_C32(0x00000083), SPH_C32(0x00000000)}, + {SPH_C32(0x80008003), SPH_C32(0x00000000)}, + {SPH_C32(0x80008088), SPH_C32(0x00000001)}, + {SPH_C32(0x80000088), SPH_C32(0x00000000)}, + {SPH_C32(0x00008000), SPH_C32(0x00000001)}, + {SPH_C32(0x80008082), SPH_C32(0x00000000)} #else - { SPH_C32(0x00000000), SPH_C32(0x00000001) }, - { SPH_C32(0x00000000), SPH_C32(0x00008082) }, - { SPH_C32(0x80000000), SPH_C32(0x0000808A) }, - { SPH_C32(0x80000000), SPH_C32(0x80008000) }, - { SPH_C32(0x00000000), SPH_C32(0x0000808B) }, - { SPH_C32(0x00000000), SPH_C32(0x80000001) }, - { SPH_C32(0x80000000), SPH_C32(0x80008081) }, - { SPH_C32(0x80000000), SPH_C32(0x00008009) }, - { SPH_C32(0x00000000), SPH_C32(0x0000008A) }, - { SPH_C32(0x00000000), SPH_C32(0x00000088) }, - { SPH_C32(0x00000000), SPH_C32(0x80008009) }, - { SPH_C32(0x00000000), SPH_C32(0x8000000A) }, - { SPH_C32(0x00000000), SPH_C32(0x8000808B) }, - { SPH_C32(0x80000000), SPH_C32(0x0000008B) }, - { SPH_C32(0x80000000), SPH_C32(0x00008089) }, - { SPH_C32(0x80000000), SPH_C32(0x00008003) }, - { SPH_C32(0x80000000), SPH_C32(0x00008002) }, - { SPH_C32(0x80000000), SPH_C32(0x00000080) }, - { SPH_C32(0x00000000), SPH_C32(0x0000800A) }, - { SPH_C32(0x80000000), SPH_C32(0x8000000A) }, - { SPH_C32(0x80000000), SPH_C32(0x80008081) }, - { SPH_C32(0x80000000), SPH_C32(0x00008080) }, - { SPH_C32(0x00000000), SPH_C32(0x80000001) }, - { SPH_C32(0x80000000), SPH_C32(0x80008008) } + {SPH_C32(0x00000000), SPH_C32(0x00000001)}, + {SPH_C32(0x00000000), SPH_C32(0x00008082)}, + {SPH_C32(0x80000000), SPH_C32(0x0000808A)}, + {SPH_C32(0x80000000), SPH_C32(0x80008000)}, + {SPH_C32(0x00000000), SPH_C32(0x0000808B)}, + {SPH_C32(0x00000000), SPH_C32(0x80000001)}, + {SPH_C32(0x80000000), SPH_C32(0x80008081)}, + {SPH_C32(0x80000000), SPH_C32(0x00008009)}, + {SPH_C32(0x00000000), SPH_C32(0x0000008A)}, + {SPH_C32(0x00000000), SPH_C32(0x00000088)}, + {SPH_C32(0x00000000), SPH_C32(0x80008009)}, + {SPH_C32(0x00000000), SPH_C32(0x8000000A)}, + {SPH_C32(0x00000000), SPH_C32(0x8000808B)}, + {SPH_C32(0x80000000), SPH_C32(0x0000008B)}, + {SPH_C32(0x80000000), SPH_C32(0x00008089)}, + {SPH_C32(0x80000000), SPH_C32(0x00008003)}, + {SPH_C32(0x80000000), SPH_C32(0x00008002)}, + {SPH_C32(0x80000000), SPH_C32(0x00000080)}, + {SPH_C32(0x00000000), SPH_C32(0x0000800A)}, + {SPH_C32(0x80000000), SPH_C32(0x8000000A)}, + {SPH_C32(0x80000000), SPH_C32(0x80008081)}, + {SPH_C32(0x80000000), SPH_C32(0x00008080)}, + {SPH_C32(0x00000000), SPH_C32(0x80000001)}, + {SPH_C32(0x80000000), SPH_C32(0x80008008)} #endif }; #if SPH_KECCAK_INTERLEAVE -#define INTERLEAVE(xl, xh) do { \ - sph_u32 l, h, t; \ - l = (xl); h = (xh); \ - t = (l ^ (l >> 1)) & SPH_C32(0x22222222); l ^= t ^ (t << 1); \ - t = (h ^ (h >> 1)) & SPH_C32(0x22222222); h ^= t ^ (t << 1); \ - t = (l ^ (l >> 2)) & SPH_C32(0x0C0C0C0C); l ^= t ^ (t << 2); \ - t = (h ^ (h >> 2)) & SPH_C32(0x0C0C0C0C); h ^= t ^ (t << 2); \ - t = (l ^ (l >> 4)) & SPH_C32(0x00F000F0); l ^= t ^ (t << 4); \ - t = (h ^ (h >> 4)) & SPH_C32(0x00F000F0); h ^= t ^ (t << 4); \ - t = (l ^ (l >> 8)) & SPH_C32(0x0000FF00); l ^= t ^ (t << 8); \ - t = (h ^ (h >> 8)) & SPH_C32(0x0000FF00); h ^= t ^ (t << 8); \ - t = (l ^ SPH_T32(h << 16)) & SPH_C32(0xFFFF0000); \ - l ^= t; h ^= t >> 16; \ - (xl) = l; (xh) = h; \ - } while (0) - -#define UNINTERLEAVE(xl, xh) do { \ - sph_u32 l, h, t; \ - l = (xl); h = (xh); \ - t = (l ^ SPH_T32(h << 16)) & SPH_C32(0xFFFF0000); \ - l ^= t; h ^= t >> 16; \ - t = (l ^ (l >> 8)) & SPH_C32(0x0000FF00); l ^= t ^ (t << 8); \ - t = (h ^ (h >> 8)) & SPH_C32(0x0000FF00); h ^= t ^ (t << 8); \ - t = (l ^ (l >> 4)) & SPH_C32(0x00F000F0); l ^= t ^ (t << 4); \ - t = (h ^ (h >> 4)) & SPH_C32(0x00F000F0); h ^= t ^ (t << 4); \ - t = (l ^ (l >> 2)) & SPH_C32(0x0C0C0C0C); l ^= t ^ (t << 2); \ - t = (h ^ (h >> 2)) & SPH_C32(0x0C0C0C0C); h ^= t ^ (t << 2); \ - t = (l ^ (l >> 1)) & SPH_C32(0x22222222); l ^= t ^ (t << 1); \ - t = (h ^ (h >> 1)) & SPH_C32(0x22222222); h ^= t ^ (t << 1); \ - (xl) = l; (xh) = h; \ - } while (0) +#define INTERLEAVE(xl, xh) \ + do { \ + sph_u32 l, h, t; \ + l = (xl); \ + h = (xh); \ + t = (l ^ (l >> 1)) & SPH_C32(0x22222222); \ + l ^= t ^ (t << 1); \ + t = (h ^ (h >> 1)) & SPH_C32(0x22222222); \ + h ^= t ^ (t << 1); \ + t = (l ^ (l >> 2)) & SPH_C32(0x0C0C0C0C); \ + l ^= t ^ (t << 2); \ + t = (h ^ (h >> 2)) & SPH_C32(0x0C0C0C0C); \ + h ^= t ^ (t << 2); \ + t = (l ^ (l >> 4)) & SPH_C32(0x00F000F0); \ + l ^= t ^ (t << 4); \ + t = (h ^ (h >> 4)) & SPH_C32(0x00F000F0); \ + h ^= t ^ (t << 4); \ + t = (l ^ (l >> 8)) & SPH_C32(0x0000FF00); \ + l ^= t ^ (t << 8); \ + t = (h ^ (h >> 8)) & SPH_C32(0x0000FF00); \ + h ^= t ^ (t << 8); \ + t = (l ^ SPH_T32(h << 16)) & SPH_C32(0xFFFF0000); \ + l ^= t; \ + h ^= t >> 16; \ + (xl) = l; \ + (xh) = h; \ + } while (0) + +#define UNINTERLEAVE(xl, xh) \ + do { \ + sph_u32 l, h, t; \ + l = (xl); \ + h = (xh); \ + t = (l ^ SPH_T32(h << 16)) & SPH_C32(0xFFFF0000); \ + l ^= t; \ + h ^= t >> 16; \ + t = (l ^ (l >> 8)) & SPH_C32(0x0000FF00); \ + l ^= t ^ (t << 8); \ + t = (h ^ (h >> 8)) & SPH_C32(0x0000FF00); \ + h ^= t ^ (t << 8); \ + t = (l ^ (l >> 4)) & SPH_C32(0x00F000F0); \ + l ^= t ^ (t << 4); \ + t = (h ^ (h >> 4)) & SPH_C32(0x00F000F0); \ + h ^= t ^ (t << 4); \ + t = (l ^ (l >> 2)) & SPH_C32(0x0C0C0C0C); \ + l ^= t ^ (t << 2); \ + t = (h ^ (h >> 2)) & SPH_C32(0x0C0C0C0C); \ + h ^= t ^ (t << 2); \ + t = (l ^ (l >> 1)) & SPH_C32(0x22222222); \ + l ^= t ^ (t << 1); \ + t = (h ^ (h >> 1)) & SPH_C32(0x22222222); \ + h ^= t ^ (t << 1); \ + (xl) = l; \ + (xh) = h; \ + } while (0) #else @@ -465,584 +498,598 @@ static const struct { #if SPH_KECCAK_NOCOPY -#define a00l (kc->u.narrow[2 * 0 + 0]) -#define a00h (kc->u.narrow[2 * 0 + 1]) -#define a10l (kc->u.narrow[2 * 1 + 0]) -#define a10h (kc->u.narrow[2 * 1 + 1]) -#define a20l (kc->u.narrow[2 * 2 + 0]) -#define a20h (kc->u.narrow[2 * 2 + 1]) -#define a30l (kc->u.narrow[2 * 3 + 0]) -#define a30h (kc->u.narrow[2 * 3 + 1]) -#define a40l (kc->u.narrow[2 * 4 + 0]) -#define a40h (kc->u.narrow[2 * 4 + 1]) -#define a01l (kc->u.narrow[2 * 5 + 0]) -#define a01h (kc->u.narrow[2 * 5 + 1]) -#define a11l (kc->u.narrow[2 * 6 + 0]) -#define a11h (kc->u.narrow[2 * 6 + 1]) -#define a21l (kc->u.narrow[2 * 7 + 0]) -#define a21h (kc->u.narrow[2 * 7 + 1]) -#define a31l (kc->u.narrow[2 * 8 + 0]) -#define a31h (kc->u.narrow[2 * 8 + 1]) -#define a41l (kc->u.narrow[2 * 9 + 0]) -#define a41h (kc->u.narrow[2 * 9 + 1]) -#define a02l (kc->u.narrow[2 * 10 + 0]) -#define a02h (kc->u.narrow[2 * 10 + 1]) -#define a12l (kc->u.narrow[2 * 11 + 0]) -#define a12h (kc->u.narrow[2 * 11 + 1]) -#define a22l (kc->u.narrow[2 * 12 + 0]) -#define a22h (kc->u.narrow[2 * 12 + 1]) -#define a32l (kc->u.narrow[2 * 13 + 0]) -#define a32h (kc->u.narrow[2 * 13 + 1]) -#define a42l (kc->u.narrow[2 * 14 + 0]) -#define a42h (kc->u.narrow[2 * 14 + 1]) -#define a03l (kc->u.narrow[2 * 15 + 0]) -#define a03h (kc->u.narrow[2 * 15 + 1]) -#define a13l (kc->u.narrow[2 * 16 + 0]) -#define a13h (kc->u.narrow[2 * 16 + 1]) -#define a23l (kc->u.narrow[2 * 17 + 0]) -#define a23h (kc->u.narrow[2 * 17 + 1]) -#define a33l (kc->u.narrow[2 * 18 + 0]) -#define a33h (kc->u.narrow[2 * 18 + 1]) -#define a43l (kc->u.narrow[2 * 19 + 0]) -#define a43h (kc->u.narrow[2 * 19 + 1]) -#define a04l (kc->u.narrow[2 * 20 + 0]) -#define a04h (kc->u.narrow[2 * 20 + 1]) -#define a14l (kc->u.narrow[2 * 21 + 0]) -#define a14h (kc->u.narrow[2 * 21 + 1]) -#define a24l (kc->u.narrow[2 * 22 + 0]) -#define a24h (kc->u.narrow[2 * 22 + 1]) -#define a34l (kc->u.narrow[2 * 23 + 0]) -#define a34h (kc->u.narrow[2 * 23 + 1]) -#define a44l (kc->u.narrow[2 * 24 + 0]) -#define a44h (kc->u.narrow[2 * 24 + 1]) +#define a00l (kc->u.narrow[2 * 0 + 0]) +#define a00h (kc->u.narrow[2 * 0 + 1]) +#define a10l (kc->u.narrow[2 * 1 + 0]) +#define a10h (kc->u.narrow[2 * 1 + 1]) +#define a20l (kc->u.narrow[2 * 2 + 0]) +#define a20h (kc->u.narrow[2 * 2 + 1]) +#define a30l (kc->u.narrow[2 * 3 + 0]) +#define a30h (kc->u.narrow[2 * 3 + 1]) +#define a40l (kc->u.narrow[2 * 4 + 0]) +#define a40h (kc->u.narrow[2 * 4 + 1]) +#define a01l (kc->u.narrow[2 * 5 + 0]) +#define a01h (kc->u.narrow[2 * 5 + 1]) +#define a11l (kc->u.narrow[2 * 6 + 0]) +#define a11h (kc->u.narrow[2 * 6 + 1]) +#define a21l (kc->u.narrow[2 * 7 + 0]) +#define a21h (kc->u.narrow[2 * 7 + 1]) +#define a31l (kc->u.narrow[2 * 8 + 0]) +#define a31h (kc->u.narrow[2 * 8 + 1]) +#define a41l (kc->u.narrow[2 * 9 + 0]) +#define a41h (kc->u.narrow[2 * 9 + 1]) +#define a02l (kc->u.narrow[2 * 10 + 0]) +#define a02h (kc->u.narrow[2 * 10 + 1]) +#define a12l (kc->u.narrow[2 * 11 + 0]) +#define a12h (kc->u.narrow[2 * 11 + 1]) +#define a22l (kc->u.narrow[2 * 12 + 0]) +#define a22h (kc->u.narrow[2 * 12 + 1]) +#define a32l (kc->u.narrow[2 * 13 + 0]) +#define a32h (kc->u.narrow[2 * 13 + 1]) +#define a42l (kc->u.narrow[2 * 14 + 0]) +#define a42h (kc->u.narrow[2 * 14 + 1]) +#define a03l (kc->u.narrow[2 * 15 + 0]) +#define a03h (kc->u.narrow[2 * 15 + 1]) +#define a13l (kc->u.narrow[2 * 16 + 0]) +#define a13h (kc->u.narrow[2 * 16 + 1]) +#define a23l (kc->u.narrow[2 * 17 + 0]) +#define a23h (kc->u.narrow[2 * 17 + 1]) +#define a33l (kc->u.narrow[2 * 18 + 0]) +#define a33h (kc->u.narrow[2 * 18 + 1]) +#define a43l (kc->u.narrow[2 * 19 + 0]) +#define a43h (kc->u.narrow[2 * 19 + 1]) +#define a04l (kc->u.narrow[2 * 20 + 0]) +#define a04h (kc->u.narrow[2 * 20 + 1]) +#define a14l (kc->u.narrow[2 * 21 + 0]) +#define a14h (kc->u.narrow[2 * 21 + 1]) +#define a24l (kc->u.narrow[2 * 22 + 0]) +#define a24h (kc->u.narrow[2 * 22 + 1]) +#define a34l (kc->u.narrow[2 * 23 + 0]) +#define a34h (kc->u.narrow[2 * 23 + 1]) +#define a44l (kc->u.narrow[2 * 24 + 0]) +#define a44h (kc->u.narrow[2 * 24 + 1]) #define DECL_STATE #define READ_STATE(state) #define WRITE_STATE(state) -#define INPUT_BUF(size) do { \ - size_t j; \ - for (j = 0; j < (size); j += 8) { \ - sph_u32 tl, th; \ - tl = sph_dec32le_aligned(buf + j + 0); \ - th = sph_dec32le_aligned(buf + j + 4); \ - INTERLEAVE(tl, th); \ - kc->u.narrow[(j >> 2) + 0] ^= tl; \ - kc->u.narrow[(j >> 2) + 1] ^= th; \ - } \ - } while (0) - -#define INPUT_BUF144 INPUT_BUF(144) -#define INPUT_BUF136 INPUT_BUF(136) -#define INPUT_BUF104 INPUT_BUF(104) -#define INPUT_BUF72 INPUT_BUF(72) +#define INPUT_BUF(size) \ + do { \ + size_t j; \ + for (j = 0; j < (size); j += 8) { \ + sph_u32 tl, th; \ + tl = sph_dec32le_aligned(buf + j + 0); \ + th = sph_dec32le_aligned(buf + j + 4); \ + INTERLEAVE(tl, th); \ + kc->u.narrow[(j >> 2) + 0] ^= tl; \ + kc->u.narrow[(j >> 2) + 1] ^= th; \ + } \ + } while (0) + +#define INPUT_BUF144 INPUT_BUF(144) +#define INPUT_BUF136 INPUT_BUF(136) +#define INPUT_BUF104 INPUT_BUF(104) +#define INPUT_BUF72 INPUT_BUF(72) #else -#define DECL_STATE \ - sph_u32 a00l, a00h, a01l, a01h, a02l, a02h, a03l, a03h, a04l, a04h; \ - sph_u32 a10l, a10h, a11l, a11h, a12l, a12h, a13l, a13h, a14l, a14h; \ - sph_u32 a20l, a20h, a21l, a21h, a22l, a22h, a23l, a23h, a24l, a24h; \ - sph_u32 a30l, a30h, a31l, a31h, a32l, a32h, a33l, a33h, a34l, a34h; \ - sph_u32 a40l, a40h, a41l, a41h, a42l, a42h, a43l, a43h, a44l, a44h; - -#define READ_STATE(state) do { \ - a00l = (state)->u.narrow[2 * 0 + 0]; \ - a00h = (state)->u.narrow[2 * 0 + 1]; \ - a10l = (state)->u.narrow[2 * 1 + 0]; \ - a10h = (state)->u.narrow[2 * 1 + 1]; \ - a20l = (state)->u.narrow[2 * 2 + 0]; \ - a20h = (state)->u.narrow[2 * 2 + 1]; \ - a30l = (state)->u.narrow[2 * 3 + 0]; \ - a30h = (state)->u.narrow[2 * 3 + 1]; \ - a40l = (state)->u.narrow[2 * 4 + 0]; \ - a40h = (state)->u.narrow[2 * 4 + 1]; \ - a01l = (state)->u.narrow[2 * 5 + 0]; \ - a01h = (state)->u.narrow[2 * 5 + 1]; \ - a11l = (state)->u.narrow[2 * 6 + 0]; \ - a11h = (state)->u.narrow[2 * 6 + 1]; \ - a21l = (state)->u.narrow[2 * 7 + 0]; \ - a21h = (state)->u.narrow[2 * 7 + 1]; \ - a31l = (state)->u.narrow[2 * 8 + 0]; \ - a31h = (state)->u.narrow[2 * 8 + 1]; \ - a41l = (state)->u.narrow[2 * 9 + 0]; \ - a41h = (state)->u.narrow[2 * 9 + 1]; \ - a02l = (state)->u.narrow[2 * 10 + 0]; \ - a02h = (state)->u.narrow[2 * 10 + 1]; \ - a12l = (state)->u.narrow[2 * 11 + 0]; \ - a12h = (state)->u.narrow[2 * 11 + 1]; \ - a22l = (state)->u.narrow[2 * 12 + 0]; \ - a22h = (state)->u.narrow[2 * 12 + 1]; \ - a32l = (state)->u.narrow[2 * 13 + 0]; \ - a32h = (state)->u.narrow[2 * 13 + 1]; \ - a42l = (state)->u.narrow[2 * 14 + 0]; \ - a42h = (state)->u.narrow[2 * 14 + 1]; \ - a03l = (state)->u.narrow[2 * 15 + 0]; \ - a03h = (state)->u.narrow[2 * 15 + 1]; \ - a13l = (state)->u.narrow[2 * 16 + 0]; \ - a13h = (state)->u.narrow[2 * 16 + 1]; \ - a23l = (state)->u.narrow[2 * 17 + 0]; \ - a23h = (state)->u.narrow[2 * 17 + 1]; \ - a33l = (state)->u.narrow[2 * 18 + 0]; \ - a33h = (state)->u.narrow[2 * 18 + 1]; \ - a43l = (state)->u.narrow[2 * 19 + 0]; \ - a43h = (state)->u.narrow[2 * 19 + 1]; \ - a04l = (state)->u.narrow[2 * 20 + 0]; \ - a04h = (state)->u.narrow[2 * 20 + 1]; \ - a14l = (state)->u.narrow[2 * 21 + 0]; \ - a14h = (state)->u.narrow[2 * 21 + 1]; \ - a24l = (state)->u.narrow[2 * 22 + 0]; \ - a24h = (state)->u.narrow[2 * 22 + 1]; \ - a34l = (state)->u.narrow[2 * 23 + 0]; \ - a34h = (state)->u.narrow[2 * 23 + 1]; \ - a44l = (state)->u.narrow[2 * 24 + 0]; \ - a44h = (state)->u.narrow[2 * 24 + 1]; \ - } while (0) - -#define WRITE_STATE(state) do { \ - (state)->u.narrow[2 * 0 + 0] = a00l; \ - (state)->u.narrow[2 * 0 + 1] = a00h; \ - (state)->u.narrow[2 * 1 + 0] = a10l; \ - (state)->u.narrow[2 * 1 + 1] = a10h; \ - (state)->u.narrow[2 * 2 + 0] = a20l; \ - (state)->u.narrow[2 * 2 + 1] = a20h; \ - (state)->u.narrow[2 * 3 + 0] = a30l; \ - (state)->u.narrow[2 * 3 + 1] = a30h; \ - (state)->u.narrow[2 * 4 + 0] = a40l; \ - (state)->u.narrow[2 * 4 + 1] = a40h; \ - (state)->u.narrow[2 * 5 + 0] = a01l; \ - (state)->u.narrow[2 * 5 + 1] = a01h; \ - (state)->u.narrow[2 * 6 + 0] = a11l; \ - (state)->u.narrow[2 * 6 + 1] = a11h; \ - (state)->u.narrow[2 * 7 + 0] = a21l; \ - (state)->u.narrow[2 * 7 + 1] = a21h; \ - (state)->u.narrow[2 * 8 + 0] = a31l; \ - (state)->u.narrow[2 * 8 + 1] = a31h; \ - (state)->u.narrow[2 * 9 + 0] = a41l; \ - (state)->u.narrow[2 * 9 + 1] = a41h; \ - (state)->u.narrow[2 * 10 + 0] = a02l; \ - (state)->u.narrow[2 * 10 + 1] = a02h; \ - (state)->u.narrow[2 * 11 + 0] = a12l; \ - (state)->u.narrow[2 * 11 + 1] = a12h; \ - (state)->u.narrow[2 * 12 + 0] = a22l; \ - (state)->u.narrow[2 * 12 + 1] = a22h; \ - (state)->u.narrow[2 * 13 + 0] = a32l; \ - (state)->u.narrow[2 * 13 + 1] = a32h; \ - (state)->u.narrow[2 * 14 + 0] = a42l; \ - (state)->u.narrow[2 * 14 + 1] = a42h; \ - (state)->u.narrow[2 * 15 + 0] = a03l; \ - (state)->u.narrow[2 * 15 + 1] = a03h; \ - (state)->u.narrow[2 * 16 + 0] = a13l; \ - (state)->u.narrow[2 * 16 + 1] = a13h; \ - (state)->u.narrow[2 * 17 + 0] = a23l; \ - (state)->u.narrow[2 * 17 + 1] = a23h; \ - (state)->u.narrow[2 * 18 + 0] = a33l; \ - (state)->u.narrow[2 * 18 + 1] = a33h; \ - (state)->u.narrow[2 * 19 + 0] = a43l; \ - (state)->u.narrow[2 * 19 + 1] = a43h; \ - (state)->u.narrow[2 * 20 + 0] = a04l; \ - (state)->u.narrow[2 * 20 + 1] = a04h; \ - (state)->u.narrow[2 * 21 + 0] = a14l; \ - (state)->u.narrow[2 * 21 + 1] = a14h; \ - (state)->u.narrow[2 * 22 + 0] = a24l; \ - (state)->u.narrow[2 * 22 + 1] = a24h; \ - (state)->u.narrow[2 * 23 + 0] = a34l; \ - (state)->u.narrow[2 * 23 + 1] = a34h; \ - (state)->u.narrow[2 * 24 + 0] = a44l; \ - (state)->u.narrow[2 * 24 + 1] = a44h; \ - } while (0) - -#define READ64(d, off) do { \ - sph_u32 tl, th; \ - tl = sph_dec32le_aligned(buf + (off)); \ - th = sph_dec32le_aligned(buf + (off) + 4); \ - INTERLEAVE(tl, th); \ - d ## l ^= tl; \ - d ## h ^= th; \ - } while (0) - -#define INPUT_BUF144 do { \ - READ64(a00, 0); \ - READ64(a10, 8); \ - READ64(a20, 16); \ - READ64(a30, 24); \ - READ64(a40, 32); \ - READ64(a01, 40); \ - READ64(a11, 48); \ - READ64(a21, 56); \ - READ64(a31, 64); \ - READ64(a41, 72); \ - READ64(a02, 80); \ - READ64(a12, 88); \ - READ64(a22, 96); \ - READ64(a32, 104); \ - READ64(a42, 112); \ - READ64(a03, 120); \ - READ64(a13, 128); \ - READ64(a23, 136); \ - } while (0) - -#define INPUT_BUF136 do { \ - READ64(a00, 0); \ - READ64(a10, 8); \ - READ64(a20, 16); \ - READ64(a30, 24); \ - READ64(a40, 32); \ - READ64(a01, 40); \ - READ64(a11, 48); \ - READ64(a21, 56); \ - READ64(a31, 64); \ - READ64(a41, 72); \ - READ64(a02, 80); \ - READ64(a12, 88); \ - READ64(a22, 96); \ - READ64(a32, 104); \ - READ64(a42, 112); \ - READ64(a03, 120); \ - READ64(a13, 128); \ - } while (0) - -#define INPUT_BUF104 do { \ - READ64(a00, 0); \ - READ64(a10, 8); \ - READ64(a20, 16); \ - READ64(a30, 24); \ - READ64(a40, 32); \ - READ64(a01, 40); \ - READ64(a11, 48); \ - READ64(a21, 56); \ - READ64(a31, 64); \ - READ64(a41, 72); \ - READ64(a02, 80); \ - READ64(a12, 88); \ - READ64(a22, 96); \ - } while (0) - -#define INPUT_BUF72 do { \ - READ64(a00, 0); \ - READ64(a10, 8); \ - READ64(a20, 16); \ - READ64(a30, 24); \ - READ64(a40, 32); \ - READ64(a01, 40); \ - READ64(a11, 48); \ - READ64(a21, 56); \ - READ64(a31, 64); \ - } while (0) - -#define INPUT_BUF(lim) do { \ - READ64(a00, 0); \ - READ64(a10, 8); \ - READ64(a20, 16); \ - READ64(a30, 24); \ - READ64(a40, 32); \ - READ64(a01, 40); \ - READ64(a11, 48); \ - READ64(a21, 56); \ - READ64(a31, 64); \ - if ((lim) == 72) \ - break; \ - READ64(a41, 72); \ - READ64(a02, 80); \ - READ64(a12, 88); \ - READ64(a22, 96); \ - if ((lim) == 104) \ - break; \ - READ64(a32, 104); \ - READ64(a42, 112); \ - READ64(a03, 120); \ - READ64(a13, 128); \ - if ((lim) == 136) \ - break; \ - READ64(a23, 136); \ - } while (0) +#define DECL_STATE \ + sph_u32 a00l, a00h, a01l, a01h, a02l, a02h, a03l, a03h, a04l, a04h; \ + sph_u32 a10l, a10h, a11l, a11h, a12l, a12h, a13l, a13h, a14l, a14h; \ + sph_u32 a20l, a20h, a21l, a21h, a22l, a22h, a23l, a23h, a24l, a24h; \ + sph_u32 a30l, a30h, a31l, a31h, a32l, a32h, a33l, a33h, a34l, a34h; \ + sph_u32 a40l, a40h, a41l, a41h, a42l, a42h, a43l, a43h, a44l, a44h; + +#define READ_STATE(state) \ + do { \ + a00l = (state)->u.narrow[2 * 0 + 0]; \ + a00h = (state)->u.narrow[2 * 0 + 1]; \ + a10l = (state)->u.narrow[2 * 1 + 0]; \ + a10h = (state)->u.narrow[2 * 1 + 1]; \ + a20l = (state)->u.narrow[2 * 2 + 0]; \ + a20h = (state)->u.narrow[2 * 2 + 1]; \ + a30l = (state)->u.narrow[2 * 3 + 0]; \ + a30h = (state)->u.narrow[2 * 3 + 1]; \ + a40l = (state)->u.narrow[2 * 4 + 0]; \ + a40h = (state)->u.narrow[2 * 4 + 1]; \ + a01l = (state)->u.narrow[2 * 5 + 0]; \ + a01h = (state)->u.narrow[2 * 5 + 1]; \ + a11l = (state)->u.narrow[2 * 6 + 0]; \ + a11h = (state)->u.narrow[2 * 6 + 1]; \ + a21l = (state)->u.narrow[2 * 7 + 0]; \ + a21h = (state)->u.narrow[2 * 7 + 1]; \ + a31l = (state)->u.narrow[2 * 8 + 0]; \ + a31h = (state)->u.narrow[2 * 8 + 1]; \ + a41l = (state)->u.narrow[2 * 9 + 0]; \ + a41h = (state)->u.narrow[2 * 9 + 1]; \ + a02l = (state)->u.narrow[2 * 10 + 0]; \ + a02h = (state)->u.narrow[2 * 10 + 1]; \ + a12l = (state)->u.narrow[2 * 11 + 0]; \ + a12h = (state)->u.narrow[2 * 11 + 1]; \ + a22l = (state)->u.narrow[2 * 12 + 0]; \ + a22h = (state)->u.narrow[2 * 12 + 1]; \ + a32l = (state)->u.narrow[2 * 13 + 0]; \ + a32h = (state)->u.narrow[2 * 13 + 1]; \ + a42l = (state)->u.narrow[2 * 14 + 0]; \ + a42h = (state)->u.narrow[2 * 14 + 1]; \ + a03l = (state)->u.narrow[2 * 15 + 0]; \ + a03h = (state)->u.narrow[2 * 15 + 1]; \ + a13l = (state)->u.narrow[2 * 16 + 0]; \ + a13h = (state)->u.narrow[2 * 16 + 1]; \ + a23l = (state)->u.narrow[2 * 17 + 0]; \ + a23h = (state)->u.narrow[2 * 17 + 1]; \ + a33l = (state)->u.narrow[2 * 18 + 0]; \ + a33h = (state)->u.narrow[2 * 18 + 1]; \ + a43l = (state)->u.narrow[2 * 19 + 0]; \ + a43h = (state)->u.narrow[2 * 19 + 1]; \ + a04l = (state)->u.narrow[2 * 20 + 0]; \ + a04h = (state)->u.narrow[2 * 20 + 1]; \ + a14l = (state)->u.narrow[2 * 21 + 0]; \ + a14h = (state)->u.narrow[2 * 21 + 1]; \ + a24l = (state)->u.narrow[2 * 22 + 0]; \ + a24h = (state)->u.narrow[2 * 22 + 1]; \ + a34l = (state)->u.narrow[2 * 23 + 0]; \ + a34h = (state)->u.narrow[2 * 23 + 1]; \ + a44l = (state)->u.narrow[2 * 24 + 0]; \ + a44h = (state)->u.narrow[2 * 24 + 1]; \ + } while (0) + +#define WRITE_STATE(state) \ + do { \ + (state)->u.narrow[2 * 0 + 0] = a00l; \ + (state)->u.narrow[2 * 0 + 1] = a00h; \ + (state)->u.narrow[2 * 1 + 0] = a10l; \ + (state)->u.narrow[2 * 1 + 1] = a10h; \ + (state)->u.narrow[2 * 2 + 0] = a20l; \ + (state)->u.narrow[2 * 2 + 1] = a20h; \ + (state)->u.narrow[2 * 3 + 0] = a30l; \ + (state)->u.narrow[2 * 3 + 1] = a30h; \ + (state)->u.narrow[2 * 4 + 0] = a40l; \ + (state)->u.narrow[2 * 4 + 1] = a40h; \ + (state)->u.narrow[2 * 5 + 0] = a01l; \ + (state)->u.narrow[2 * 5 + 1] = a01h; \ + (state)->u.narrow[2 * 6 + 0] = a11l; \ + (state)->u.narrow[2 * 6 + 1] = a11h; \ + (state)->u.narrow[2 * 7 + 0] = a21l; \ + (state)->u.narrow[2 * 7 + 1] = a21h; \ + (state)->u.narrow[2 * 8 + 0] = a31l; \ + (state)->u.narrow[2 * 8 + 1] = a31h; \ + (state)->u.narrow[2 * 9 + 0] = a41l; \ + (state)->u.narrow[2 * 9 + 1] = a41h; \ + (state)->u.narrow[2 * 10 + 0] = a02l; \ + (state)->u.narrow[2 * 10 + 1] = a02h; \ + (state)->u.narrow[2 * 11 + 0] = a12l; \ + (state)->u.narrow[2 * 11 + 1] = a12h; \ + (state)->u.narrow[2 * 12 + 0] = a22l; \ + (state)->u.narrow[2 * 12 + 1] = a22h; \ + (state)->u.narrow[2 * 13 + 0] = a32l; \ + (state)->u.narrow[2 * 13 + 1] = a32h; \ + (state)->u.narrow[2 * 14 + 0] = a42l; \ + (state)->u.narrow[2 * 14 + 1] = a42h; \ + (state)->u.narrow[2 * 15 + 0] = a03l; \ + (state)->u.narrow[2 * 15 + 1] = a03h; \ + (state)->u.narrow[2 * 16 + 0] = a13l; \ + (state)->u.narrow[2 * 16 + 1] = a13h; \ + (state)->u.narrow[2 * 17 + 0] = a23l; \ + (state)->u.narrow[2 * 17 + 1] = a23h; \ + (state)->u.narrow[2 * 18 + 0] = a33l; \ + (state)->u.narrow[2 * 18 + 1] = a33h; \ + (state)->u.narrow[2 * 19 + 0] = a43l; \ + (state)->u.narrow[2 * 19 + 1] = a43h; \ + (state)->u.narrow[2 * 20 + 0] = a04l; \ + (state)->u.narrow[2 * 20 + 1] = a04h; \ + (state)->u.narrow[2 * 21 + 0] = a14l; \ + (state)->u.narrow[2 * 21 + 1] = a14h; \ + (state)->u.narrow[2 * 22 + 0] = a24l; \ + (state)->u.narrow[2 * 22 + 1] = a24h; \ + (state)->u.narrow[2 * 23 + 0] = a34l; \ + (state)->u.narrow[2 * 23 + 1] = a34h; \ + (state)->u.narrow[2 * 24 + 0] = a44l; \ + (state)->u.narrow[2 * 24 + 1] = a44h; \ + } while (0) + +#define READ64(d, off) \ + do { \ + sph_u32 tl, th; \ + tl = sph_dec32le_aligned(buf + (off)); \ + th = sph_dec32le_aligned(buf + (off) + 4); \ + INTERLEAVE(tl, th); \ + d##l ^= tl; \ + d##h ^= th; \ + } while (0) + +#define INPUT_BUF144 \ + do { \ + READ64(a00, 0); \ + READ64(a10, 8); \ + READ64(a20, 16); \ + READ64(a30, 24); \ + READ64(a40, 32); \ + READ64(a01, 40); \ + READ64(a11, 48); \ + READ64(a21, 56); \ + READ64(a31, 64); \ + READ64(a41, 72); \ + READ64(a02, 80); \ + READ64(a12, 88); \ + READ64(a22, 96); \ + READ64(a32, 104); \ + READ64(a42, 112); \ + READ64(a03, 120); \ + READ64(a13, 128); \ + READ64(a23, 136); \ + } while (0) + +#define INPUT_BUF136 \ + do { \ + READ64(a00, 0); \ + READ64(a10, 8); \ + READ64(a20, 16); \ + READ64(a30, 24); \ + READ64(a40, 32); \ + READ64(a01, 40); \ + READ64(a11, 48); \ + READ64(a21, 56); \ + READ64(a31, 64); \ + READ64(a41, 72); \ + READ64(a02, 80); \ + READ64(a12, 88); \ + READ64(a22, 96); \ + READ64(a32, 104); \ + READ64(a42, 112); \ + READ64(a03, 120); \ + READ64(a13, 128); \ + } while (0) + +#define INPUT_BUF104 \ + do { \ + READ64(a00, 0); \ + READ64(a10, 8); \ + READ64(a20, 16); \ + READ64(a30, 24); \ + READ64(a40, 32); \ + READ64(a01, 40); \ + READ64(a11, 48); \ + READ64(a21, 56); \ + READ64(a31, 64); \ + READ64(a41, 72); \ + READ64(a02, 80); \ + READ64(a12, 88); \ + READ64(a22, 96); \ + } while (0) + +#define INPUT_BUF72 \ + do { \ + READ64(a00, 0); \ + READ64(a10, 8); \ + READ64(a20, 16); \ + READ64(a30, 24); \ + READ64(a40, 32); \ + READ64(a01, 40); \ + READ64(a11, 48); \ + READ64(a21, 56); \ + READ64(a31, 64); \ + } while (0) + +#define INPUT_BUF(lim) \ + do { \ + READ64(a00, 0); \ + READ64(a10, 8); \ + READ64(a20, 16); \ + READ64(a30, 24); \ + READ64(a40, 32); \ + READ64(a01, 40); \ + READ64(a11, 48); \ + READ64(a21, 56); \ + READ64(a31, 64); \ + if ((lim) == 72) \ + break; \ + READ64(a41, 72); \ + READ64(a02, 80); \ + READ64(a12, 88); \ + READ64(a22, 96); \ + if ((lim) == 104) \ + break; \ + READ64(a32, 104); \ + READ64(a42, 112); \ + READ64(a03, 120); \ + READ64(a13, 128); \ + if ((lim) == 136) \ + break; \ + READ64(a23, 136); \ + } while (0) #endif -#define DECL64(x) sph_u64 x ## l, x ## h -#define MOV64(d, s) (d ## l = s ## l, d ## h = s ## h) -#define XOR64(d, a, b) (d ## l = a ## l ^ b ## l, d ## h = a ## h ^ b ## h) -#define AND64(d, a, b) (d ## l = a ## l & b ## l, d ## h = a ## h & b ## h) -#define OR64(d, a, b) (d ## l = a ## l | b ## l, d ## h = a ## h | b ## h) -#define NOT64(d, s) (d ## l = SPH_T32(~s ## l), d ## h = SPH_T32(~s ## h)) -#define ROL64(d, v, n) ROL64_ ## n(d, v) +#define DECL64(x) sph_u64 x##l, x##h +#define MOV64(d, s) (d##l = s##l, d##h = s##h) +#define XOR64(d, a, b) (d##l = a##l ^ b##l, d##h = a##h ^ b##h) +#define AND64(d, a, b) (d##l = a##l & b##l, d##h = a##h & b##h) +#define OR64(d, a, b) (d##l = a##l | b##l, d##h = a##h | b##h) +#define NOT64(d, s) (d##l = SPH_T32(~s##l), d##h = SPH_T32(~s##h)) +#define ROL64(d, v, n) ROL64_##n(d, v) #if SPH_KECCAK_INTERLEAVE -#define ROL64_odd1(d, v) do { \ - sph_u32 tmp; \ - tmp = v ## l; \ - d ## l = SPH_T32(v ## h << 1) | (v ## h >> 31); \ - d ## h = tmp; \ - } while (0) - -#define ROL64_odd63(d, v) do { \ - sph_u32 tmp; \ - tmp = SPH_T32(v ## l << 31) | (v ## l >> 1); \ - d ## l = v ## h; \ - d ## h = tmp; \ - } while (0) - -#define ROL64_odd(d, v, n) do { \ - sph_u32 tmp; \ - tmp = SPH_T32(v ## l << (n - 1)) | (v ## l >> (33 - n)); \ - d ## l = SPH_T32(v ## h << n) | (v ## h >> (32 - n)); \ - d ## h = tmp; \ - } while (0) - -#define ROL64_even(d, v, n) do { \ - d ## l = SPH_T32(v ## l << n) | (v ## l >> (32 - n)); \ - d ## h = SPH_T32(v ## h << n) | (v ## h >> (32 - n)); \ - } while (0) +#define ROL64_odd1(d, v) \ + do { \ + sph_u32 tmp; \ + tmp = v##l; \ + d##l = SPH_T32(v##h << 1) | (v##h >> 31); \ + d##h = tmp; \ + } while (0) + +#define ROL64_odd63(d, v) \ + do { \ + sph_u32 tmp; \ + tmp = SPH_T32(v##l << 31) | (v##l >> 1); \ + d##l = v##h; \ + d##h = tmp; \ + } while (0) + +#define ROL64_odd(d, v, n) \ + do { \ + sph_u32 tmp; \ + tmp = SPH_T32(v##l << (n - 1)) | (v##l >> (33 - n)); \ + d##l = SPH_T32(v##h << n) | (v##h >> (32 - n)); \ + d##h = tmp; \ + } while (0) + +#define ROL64_even(d, v, n) \ + do { \ + d##l = SPH_T32(v##l << n) | (v##l >> (32 - n)); \ + d##h = SPH_T32(v##h << n) | (v##h >> (32 - n)); \ + } while (0) #define ROL64_0(d, v) -#define ROL64_1(d, v) ROL64_odd1(d, v) -#define ROL64_2(d, v) ROL64_even(d, v, 1) -#define ROL64_3(d, v) ROL64_odd( d, v, 2) -#define ROL64_4(d, v) ROL64_even(d, v, 2) -#define ROL64_5(d, v) ROL64_odd( d, v, 3) -#define ROL64_6(d, v) ROL64_even(d, v, 3) -#define ROL64_7(d, v) ROL64_odd( d, v, 4) -#define ROL64_8(d, v) ROL64_even(d, v, 4) -#define ROL64_9(d, v) ROL64_odd( d, v, 5) -#define ROL64_10(d, v) ROL64_even(d, v, 5) -#define ROL64_11(d, v) ROL64_odd( d, v, 6) -#define ROL64_12(d, v) ROL64_even(d, v, 6) -#define ROL64_13(d, v) ROL64_odd( d, v, 7) -#define ROL64_14(d, v) ROL64_even(d, v, 7) -#define ROL64_15(d, v) ROL64_odd( d, v, 8) -#define ROL64_16(d, v) ROL64_even(d, v, 8) -#define ROL64_17(d, v) ROL64_odd( d, v, 9) -#define ROL64_18(d, v) ROL64_even(d, v, 9) -#define ROL64_19(d, v) ROL64_odd( d, v, 10) -#define ROL64_20(d, v) ROL64_even(d, v, 10) -#define ROL64_21(d, v) ROL64_odd( d, v, 11) -#define ROL64_22(d, v) ROL64_even(d, v, 11) -#define ROL64_23(d, v) ROL64_odd( d, v, 12) -#define ROL64_24(d, v) ROL64_even(d, v, 12) -#define ROL64_25(d, v) ROL64_odd( d, v, 13) -#define ROL64_26(d, v) ROL64_even(d, v, 13) -#define ROL64_27(d, v) ROL64_odd( d, v, 14) -#define ROL64_28(d, v) ROL64_even(d, v, 14) -#define ROL64_29(d, v) ROL64_odd( d, v, 15) -#define ROL64_30(d, v) ROL64_even(d, v, 15) -#define ROL64_31(d, v) ROL64_odd( d, v, 16) -#define ROL64_32(d, v) ROL64_even(d, v, 16) -#define ROL64_33(d, v) ROL64_odd( d, v, 17) -#define ROL64_34(d, v) ROL64_even(d, v, 17) -#define ROL64_35(d, v) ROL64_odd( d, v, 18) -#define ROL64_36(d, v) ROL64_even(d, v, 18) -#define ROL64_37(d, v) ROL64_odd( d, v, 19) -#define ROL64_38(d, v) ROL64_even(d, v, 19) -#define ROL64_39(d, v) ROL64_odd( d, v, 20) -#define ROL64_40(d, v) ROL64_even(d, v, 20) -#define ROL64_41(d, v) ROL64_odd( d, v, 21) -#define ROL64_42(d, v) ROL64_even(d, v, 21) -#define ROL64_43(d, v) ROL64_odd( d, v, 22) -#define ROL64_44(d, v) ROL64_even(d, v, 22) -#define ROL64_45(d, v) ROL64_odd( d, v, 23) -#define ROL64_46(d, v) ROL64_even(d, v, 23) -#define ROL64_47(d, v) ROL64_odd( d, v, 24) -#define ROL64_48(d, v) ROL64_even(d, v, 24) -#define ROL64_49(d, v) ROL64_odd( d, v, 25) -#define ROL64_50(d, v) ROL64_even(d, v, 25) -#define ROL64_51(d, v) ROL64_odd( d, v, 26) -#define ROL64_52(d, v) ROL64_even(d, v, 26) -#define ROL64_53(d, v) ROL64_odd( d, v, 27) -#define ROL64_54(d, v) ROL64_even(d, v, 27) -#define ROL64_55(d, v) ROL64_odd( d, v, 28) -#define ROL64_56(d, v) ROL64_even(d, v, 28) -#define ROL64_57(d, v) ROL64_odd( d, v, 29) -#define ROL64_58(d, v) ROL64_even(d, v, 29) -#define ROL64_59(d, v) ROL64_odd( d, v, 30) -#define ROL64_60(d, v) ROL64_even(d, v, 30) -#define ROL64_61(d, v) ROL64_odd( d, v, 31) -#define ROL64_62(d, v) ROL64_even(d, v, 31) -#define ROL64_63(d, v) ROL64_odd63(d, v) +#define ROL64_1(d, v) ROL64_odd1(d, v) +#define ROL64_2(d, v) ROL64_even(d, v, 1) +#define ROL64_3(d, v) ROL64_odd(d, v, 2) +#define ROL64_4(d, v) ROL64_even(d, v, 2) +#define ROL64_5(d, v) ROL64_odd(d, v, 3) +#define ROL64_6(d, v) ROL64_even(d, v, 3) +#define ROL64_7(d, v) ROL64_odd(d, v, 4) +#define ROL64_8(d, v) ROL64_even(d, v, 4) +#define ROL64_9(d, v) ROL64_odd(d, v, 5) +#define ROL64_10(d, v) ROL64_even(d, v, 5) +#define ROL64_11(d, v) ROL64_odd(d, v, 6) +#define ROL64_12(d, v) ROL64_even(d, v, 6) +#define ROL64_13(d, v) ROL64_odd(d, v, 7) +#define ROL64_14(d, v) ROL64_even(d, v, 7) +#define ROL64_15(d, v) ROL64_odd(d, v, 8) +#define ROL64_16(d, v) ROL64_even(d, v, 8) +#define ROL64_17(d, v) ROL64_odd(d, v, 9) +#define ROL64_18(d, v) ROL64_even(d, v, 9) +#define ROL64_19(d, v) ROL64_odd(d, v, 10) +#define ROL64_20(d, v) ROL64_even(d, v, 10) +#define ROL64_21(d, v) ROL64_odd(d, v, 11) +#define ROL64_22(d, v) ROL64_even(d, v, 11) +#define ROL64_23(d, v) ROL64_odd(d, v, 12) +#define ROL64_24(d, v) ROL64_even(d, v, 12) +#define ROL64_25(d, v) ROL64_odd(d, v, 13) +#define ROL64_26(d, v) ROL64_even(d, v, 13) +#define ROL64_27(d, v) ROL64_odd(d, v, 14) +#define ROL64_28(d, v) ROL64_even(d, v, 14) +#define ROL64_29(d, v) ROL64_odd(d, v, 15) +#define ROL64_30(d, v) ROL64_even(d, v, 15) +#define ROL64_31(d, v) ROL64_odd(d, v, 16) +#define ROL64_32(d, v) ROL64_even(d, v, 16) +#define ROL64_33(d, v) ROL64_odd(d, v, 17) +#define ROL64_34(d, v) ROL64_even(d, v, 17) +#define ROL64_35(d, v) ROL64_odd(d, v, 18) +#define ROL64_36(d, v) ROL64_even(d, v, 18) +#define ROL64_37(d, v) ROL64_odd(d, v, 19) +#define ROL64_38(d, v) ROL64_even(d, v, 19) +#define ROL64_39(d, v) ROL64_odd(d, v, 20) +#define ROL64_40(d, v) ROL64_even(d, v, 20) +#define ROL64_41(d, v) ROL64_odd(d, v, 21) +#define ROL64_42(d, v) ROL64_even(d, v, 21) +#define ROL64_43(d, v) ROL64_odd(d, v, 22) +#define ROL64_44(d, v) ROL64_even(d, v, 22) +#define ROL64_45(d, v) ROL64_odd(d, v, 23) +#define ROL64_46(d, v) ROL64_even(d, v, 23) +#define ROL64_47(d, v) ROL64_odd(d, v, 24) +#define ROL64_48(d, v) ROL64_even(d, v, 24) +#define ROL64_49(d, v) ROL64_odd(d, v, 25) +#define ROL64_50(d, v) ROL64_even(d, v, 25) +#define ROL64_51(d, v) ROL64_odd(d, v, 26) +#define ROL64_52(d, v) ROL64_even(d, v, 26) +#define ROL64_53(d, v) ROL64_odd(d, v, 27) +#define ROL64_54(d, v) ROL64_even(d, v, 27) +#define ROL64_55(d, v) ROL64_odd(d, v, 28) +#define ROL64_56(d, v) ROL64_even(d, v, 28) +#define ROL64_57(d, v) ROL64_odd(d, v, 29) +#define ROL64_58(d, v) ROL64_even(d, v, 29) +#define ROL64_59(d, v) ROL64_odd(d, v, 30) +#define ROL64_60(d, v) ROL64_even(d, v, 30) +#define ROL64_61(d, v) ROL64_odd(d, v, 31) +#define ROL64_62(d, v) ROL64_even(d, v, 31) +#define ROL64_63(d, v) ROL64_odd63(d, v) #else -#define ROL64_small(d, v, n) do { \ - sph_u32 tmp; \ - tmp = SPH_T32(v ## l << n) | (v ## h >> (32 - n)); \ - d ## h = SPH_T32(v ## h << n) | (v ## l >> (32 - n)); \ - d ## l = tmp; \ - } while (0) - -#define ROL64_0(d, v) 0 -#define ROL64_1(d, v) ROL64_small(d, v, 1) -#define ROL64_2(d, v) ROL64_small(d, v, 2) -#define ROL64_3(d, v) ROL64_small(d, v, 3) -#define ROL64_4(d, v) ROL64_small(d, v, 4) -#define ROL64_5(d, v) ROL64_small(d, v, 5) -#define ROL64_6(d, v) ROL64_small(d, v, 6) -#define ROL64_7(d, v) ROL64_small(d, v, 7) -#define ROL64_8(d, v) ROL64_small(d, v, 8) -#define ROL64_9(d, v) ROL64_small(d, v, 9) -#define ROL64_10(d, v) ROL64_small(d, v, 10) -#define ROL64_11(d, v) ROL64_small(d, v, 11) -#define ROL64_12(d, v) ROL64_small(d, v, 12) -#define ROL64_13(d, v) ROL64_small(d, v, 13) -#define ROL64_14(d, v) ROL64_small(d, v, 14) -#define ROL64_15(d, v) ROL64_small(d, v, 15) -#define ROL64_16(d, v) ROL64_small(d, v, 16) -#define ROL64_17(d, v) ROL64_small(d, v, 17) -#define ROL64_18(d, v) ROL64_small(d, v, 18) -#define ROL64_19(d, v) ROL64_small(d, v, 19) -#define ROL64_20(d, v) ROL64_small(d, v, 20) -#define ROL64_21(d, v) ROL64_small(d, v, 21) -#define ROL64_22(d, v) ROL64_small(d, v, 22) -#define ROL64_23(d, v) ROL64_small(d, v, 23) -#define ROL64_24(d, v) ROL64_small(d, v, 24) -#define ROL64_25(d, v) ROL64_small(d, v, 25) -#define ROL64_26(d, v) ROL64_small(d, v, 26) -#define ROL64_27(d, v) ROL64_small(d, v, 27) -#define ROL64_28(d, v) ROL64_small(d, v, 28) -#define ROL64_29(d, v) ROL64_small(d, v, 29) -#define ROL64_30(d, v) ROL64_small(d, v, 30) -#define ROL64_31(d, v) ROL64_small(d, v, 31) - -#define ROL64_32(d, v) do { \ - sph_u32 tmp; \ - tmp = v ## l; \ - d ## l = v ## h; \ - d ## h = tmp; \ - } while (0) - -#define ROL64_big(d, v, n) do { \ - sph_u32 trl, trh; \ - ROL64_small(tr, v, n); \ - d ## h = trl; \ - d ## l = trh; \ - } while (0) - -#define ROL64_33(d, v) ROL64_big(d, v, 1) -#define ROL64_34(d, v) ROL64_big(d, v, 2) -#define ROL64_35(d, v) ROL64_big(d, v, 3) -#define ROL64_36(d, v) ROL64_big(d, v, 4) -#define ROL64_37(d, v) ROL64_big(d, v, 5) -#define ROL64_38(d, v) ROL64_big(d, v, 6) -#define ROL64_39(d, v) ROL64_big(d, v, 7) -#define ROL64_40(d, v) ROL64_big(d, v, 8) -#define ROL64_41(d, v) ROL64_big(d, v, 9) -#define ROL64_42(d, v) ROL64_big(d, v, 10) -#define ROL64_43(d, v) ROL64_big(d, v, 11) -#define ROL64_44(d, v) ROL64_big(d, v, 12) -#define ROL64_45(d, v) ROL64_big(d, v, 13) -#define ROL64_46(d, v) ROL64_big(d, v, 14) -#define ROL64_47(d, v) ROL64_big(d, v, 15) -#define ROL64_48(d, v) ROL64_big(d, v, 16) -#define ROL64_49(d, v) ROL64_big(d, v, 17) -#define ROL64_50(d, v) ROL64_big(d, v, 18) -#define ROL64_51(d, v) ROL64_big(d, v, 19) -#define ROL64_52(d, v) ROL64_big(d, v, 20) -#define ROL64_53(d, v) ROL64_big(d, v, 21) -#define ROL64_54(d, v) ROL64_big(d, v, 22) -#define ROL64_55(d, v) ROL64_big(d, v, 23) -#define ROL64_56(d, v) ROL64_big(d, v, 24) -#define ROL64_57(d, v) ROL64_big(d, v, 25) -#define ROL64_58(d, v) ROL64_big(d, v, 26) -#define ROL64_59(d, v) ROL64_big(d, v, 27) -#define ROL64_60(d, v) ROL64_big(d, v, 28) -#define ROL64_61(d, v) ROL64_big(d, v, 29) -#define ROL64_62(d, v) ROL64_big(d, v, 30) -#define ROL64_63(d, v) ROL64_big(d, v, 31) +#define ROL64_small(d, v, n) \ + do { \ + sph_u32 tmp; \ + tmp = SPH_T32(v##l << n) | (v##h >> (32 - n)); \ + d##h = SPH_T32(v##h << n) | (v##l >> (32 - n)); \ + d##l = tmp; \ + } while (0) + +#define ROL64_0(d, v) 0 +#define ROL64_1(d, v) ROL64_small(d, v, 1) +#define ROL64_2(d, v) ROL64_small(d, v, 2) +#define ROL64_3(d, v) ROL64_small(d, v, 3) +#define ROL64_4(d, v) ROL64_small(d, v, 4) +#define ROL64_5(d, v) ROL64_small(d, v, 5) +#define ROL64_6(d, v) ROL64_small(d, v, 6) +#define ROL64_7(d, v) ROL64_small(d, v, 7) +#define ROL64_8(d, v) ROL64_small(d, v, 8) +#define ROL64_9(d, v) ROL64_small(d, v, 9) +#define ROL64_10(d, v) ROL64_small(d, v, 10) +#define ROL64_11(d, v) ROL64_small(d, v, 11) +#define ROL64_12(d, v) ROL64_small(d, v, 12) +#define ROL64_13(d, v) ROL64_small(d, v, 13) +#define ROL64_14(d, v) ROL64_small(d, v, 14) +#define ROL64_15(d, v) ROL64_small(d, v, 15) +#define ROL64_16(d, v) ROL64_small(d, v, 16) +#define ROL64_17(d, v) ROL64_small(d, v, 17) +#define ROL64_18(d, v) ROL64_small(d, v, 18) +#define ROL64_19(d, v) ROL64_small(d, v, 19) +#define ROL64_20(d, v) ROL64_small(d, v, 20) +#define ROL64_21(d, v) ROL64_small(d, v, 21) +#define ROL64_22(d, v) ROL64_small(d, v, 22) +#define ROL64_23(d, v) ROL64_small(d, v, 23) +#define ROL64_24(d, v) ROL64_small(d, v, 24) +#define ROL64_25(d, v) ROL64_small(d, v, 25) +#define ROL64_26(d, v) ROL64_small(d, v, 26) +#define ROL64_27(d, v) ROL64_small(d, v, 27) +#define ROL64_28(d, v) ROL64_small(d, v, 28) +#define ROL64_29(d, v) ROL64_small(d, v, 29) +#define ROL64_30(d, v) ROL64_small(d, v, 30) +#define ROL64_31(d, v) ROL64_small(d, v, 31) + +#define ROL64_32(d, v) \ + do { \ + sph_u32 tmp; \ + tmp = v##l; \ + d##l = v##h; \ + d##h = tmp; \ + } while (0) + +#define ROL64_big(d, v, n) \ + do { \ + sph_u32 trl, trh; \ + ROL64_small(tr, v, n); \ + d##h = trl; \ + d##l = trh; \ + } while (0) + +#define ROL64_33(d, v) ROL64_big(d, v, 1) +#define ROL64_34(d, v) ROL64_big(d, v, 2) +#define ROL64_35(d, v) ROL64_big(d, v, 3) +#define ROL64_36(d, v) ROL64_big(d, v, 4) +#define ROL64_37(d, v) ROL64_big(d, v, 5) +#define ROL64_38(d, v) ROL64_big(d, v, 6) +#define ROL64_39(d, v) ROL64_big(d, v, 7) +#define ROL64_40(d, v) ROL64_big(d, v, 8) +#define ROL64_41(d, v) ROL64_big(d, v, 9) +#define ROL64_42(d, v) ROL64_big(d, v, 10) +#define ROL64_43(d, v) ROL64_big(d, v, 11) +#define ROL64_44(d, v) ROL64_big(d, v, 12) +#define ROL64_45(d, v) ROL64_big(d, v, 13) +#define ROL64_46(d, v) ROL64_big(d, v, 14) +#define ROL64_47(d, v) ROL64_big(d, v, 15) +#define ROL64_48(d, v) ROL64_big(d, v, 16) +#define ROL64_49(d, v) ROL64_big(d, v, 17) +#define ROL64_50(d, v) ROL64_big(d, v, 18) +#define ROL64_51(d, v) ROL64_big(d, v, 19) +#define ROL64_52(d, v) ROL64_big(d, v, 20) +#define ROL64_53(d, v) ROL64_big(d, v, 21) +#define ROL64_54(d, v) ROL64_big(d, v, 22) +#define ROL64_55(d, v) ROL64_big(d, v, 23) +#define ROL64_56(d, v) ROL64_big(d, v, 24) +#define ROL64_57(d, v) ROL64_big(d, v, 25) +#define ROL64_58(d, v) ROL64_big(d, v, 26) +#define ROL64_59(d, v) ROL64_big(d, v, 27) +#define ROL64_60(d, v) ROL64_big(d, v, 28) +#define ROL64_61(d, v) ROL64_big(d, v, 29) +#define ROL64_62(d, v) ROL64_big(d, v, 30) +#define ROL64_63(d, v) ROL64_big(d, v, 31) #endif -#define XOR64_IOTA(d, s, k) \ - (d ## l = s ## l ^ k.low, d ## h = s ## h ^ k.high) +#define XOR64_IOTA(d, s, k) (d##l = s##l ^ k.low, d##h = s##h ^ k.high) #endif -#define TH_ELT(t, c0, c1, c2, c3, c4, d0, d1, d2, d3, d4) do { \ - DECL64(tt0); \ - DECL64(tt1); \ - DECL64(tt2); \ - DECL64(tt3); \ - XOR64(tt0, d0, d1); \ - XOR64(tt1, d2, d3); \ - XOR64(tt0, tt0, d4); \ - XOR64(tt0, tt0, tt1); \ - ROL64(tt0, tt0, 1); \ - XOR64(tt2, c0, c1); \ - XOR64(tt3, c2, c3); \ - XOR64(tt0, tt0, c4); \ - XOR64(tt2, tt2, tt3); \ - XOR64(t, tt0, tt2); \ - } while (0) - -#define THETA(b00, b01, b02, b03, b04, b10, b11, b12, b13, b14, \ - b20, b21, b22, b23, b24, b30, b31, b32, b33, b34, \ - b40, b41, b42, b43, b44) \ - do { \ - DECL64(t0); \ - DECL64(t1); \ - DECL64(t2); \ - DECL64(t3); \ - DECL64(t4); \ - TH_ELT(t0, b40, b41, b42, b43, b44, b10, b11, b12, b13, b14); \ - TH_ELT(t1, b00, b01, b02, b03, b04, b20, b21, b22, b23, b24); \ - TH_ELT(t2, b10, b11, b12, b13, b14, b30, b31, b32, b33, b34); \ - TH_ELT(t3, b20, b21, b22, b23, b24, b40, b41, b42, b43, b44); \ - TH_ELT(t4, b30, b31, b32, b33, b34, b00, b01, b02, b03, b04); \ - XOR64(b00, b00, t0); \ - XOR64(b01, b01, t0); \ - XOR64(b02, b02, t0); \ - XOR64(b03, b03, t0); \ - XOR64(b04, b04, t0); \ - XOR64(b10, b10, t1); \ - XOR64(b11, b11, t1); \ - XOR64(b12, b12, t1); \ - XOR64(b13, b13, t1); \ - XOR64(b14, b14, t1); \ - XOR64(b20, b20, t2); \ - XOR64(b21, b21, t2); \ - XOR64(b22, b22, t2); \ - XOR64(b23, b23, t2); \ - XOR64(b24, b24, t2); \ - XOR64(b30, b30, t3); \ - XOR64(b31, b31, t3); \ - XOR64(b32, b32, t3); \ - XOR64(b33, b33, t3); \ - XOR64(b34, b34, t3); \ - XOR64(b40, b40, t4); \ - XOR64(b41, b41, t4); \ - XOR64(b42, b42, t4); \ - XOR64(b43, b43, t4); \ - XOR64(b44, b44, t4); \ - } while (0) - -#define RHO(b00, b01, b02, b03, b04, b10, b11, b12, b13, b14, \ - b20, b21, b22, b23, b24, b30, b31, b32, b33, b34, \ - b40, b41, b42, b43, b44) \ - do { \ - /* ROL64(b00, b00, 0); */ \ - ROL64(b01, b01, 36); \ - ROL64(b02, b02, 3); \ - ROL64(b03, b03, 41); \ - ROL64(b04, b04, 18); \ - ROL64(b10, b10, 1); \ - ROL64(b11, b11, 44); \ - ROL64(b12, b12, 10); \ - ROL64(b13, b13, 45); \ - ROL64(b14, b14, 2); \ - ROL64(b20, b20, 62); \ - ROL64(b21, b21, 6); \ - ROL64(b22, b22, 43); \ - ROL64(b23, b23, 15); \ - ROL64(b24, b24, 61); \ - ROL64(b30, b30, 28); \ - ROL64(b31, b31, 55); \ - ROL64(b32, b32, 25); \ - ROL64(b33, b33, 21); \ - ROL64(b34, b34, 56); \ - ROL64(b40, b40, 27); \ - ROL64(b41, b41, 20); \ - ROL64(b42, b42, 39); \ - ROL64(b43, b43, 8); \ - ROL64(b44, b44, 14); \ - } while (0) +#define TH_ELT(t, c0, c1, c2, c3, c4, d0, d1, d2, d3, d4) \ + do { \ + DECL64(tt0); \ + DECL64(tt1); \ + DECL64(tt2); \ + DECL64(tt3); \ + XOR64(tt0, d0, d1); \ + XOR64(tt1, d2, d3); \ + XOR64(tt0, tt0, d4); \ + XOR64(tt0, tt0, tt1); \ + ROL64(tt0, tt0, 1); \ + XOR64(tt2, c0, c1); \ + XOR64(tt3, c2, c3); \ + XOR64(tt0, tt0, c4); \ + XOR64(tt2, tt2, tt3); \ + XOR64(t, tt0, tt2); \ + } while (0) + +#define THETA(b00, b01, b02, b03, b04, b10, b11, b12, b13, b14, b20, b21, b22, \ + b23, b24, b30, b31, b32, b33, b34, b40, b41, b42, b43, b44) \ + do { \ + DECL64(t0); \ + DECL64(t1); \ + DECL64(t2); \ + DECL64(t3); \ + DECL64(t4); \ + TH_ELT(t0, b40, b41, b42, b43, b44, b10, b11, b12, b13, b14); \ + TH_ELT(t1, b00, b01, b02, b03, b04, b20, b21, b22, b23, b24); \ + TH_ELT(t2, b10, b11, b12, b13, b14, b30, b31, b32, b33, b34); \ + TH_ELT(t3, b20, b21, b22, b23, b24, b40, b41, b42, b43, b44); \ + TH_ELT(t4, b30, b31, b32, b33, b34, b00, b01, b02, b03, b04); \ + XOR64(b00, b00, t0); \ + XOR64(b01, b01, t0); \ + XOR64(b02, b02, t0); \ + XOR64(b03, b03, t0); \ + XOR64(b04, b04, t0); \ + XOR64(b10, b10, t1); \ + XOR64(b11, b11, t1); \ + XOR64(b12, b12, t1); \ + XOR64(b13, b13, t1); \ + XOR64(b14, b14, t1); \ + XOR64(b20, b20, t2); \ + XOR64(b21, b21, t2); \ + XOR64(b22, b22, t2); \ + XOR64(b23, b23, t2); \ + XOR64(b24, b24, t2); \ + XOR64(b30, b30, t3); \ + XOR64(b31, b31, t3); \ + XOR64(b32, b32, t3); \ + XOR64(b33, b33, t3); \ + XOR64(b34, b34, t3); \ + XOR64(b40, b40, t4); \ + XOR64(b41, b41, t4); \ + XOR64(b42, b42, t4); \ + XOR64(b43, b43, t4); \ + XOR64(b44, b44, t4); \ + } while (0) + +#define RHO(b00, b01, b02, b03, b04, b10, b11, b12, b13, b14, b20, b21, b22, \ + b23, b24, b30, b31, b32, b33, b34, b40, b41, b42, b43, b44) \ + do { \ + /* ROL64(b00, b00, 0); */ \ + ROL64(b01, b01, 36); \ + ROL64(b02, b02, 3); \ + ROL64(b03, b03, 41); \ + ROL64(b04, b04, 18); \ + ROL64(b10, b10, 1); \ + ROL64(b11, b11, 44); \ + ROL64(b12, b12, 10); \ + ROL64(b13, b13, 45); \ + ROL64(b14, b14, 2); \ + ROL64(b20, b20, 62); \ + ROL64(b21, b21, 6); \ + ROL64(b22, b22, 43); \ + ROL64(b23, b23, 15); \ + ROL64(b24, b24, 61); \ + ROL64(b30, b30, 28); \ + ROL64(b31, b31, 55); \ + ROL64(b32, b32, 25); \ + ROL64(b33, b33, 21); \ + ROL64(b34, b34, 56); \ + ROL64(b40, b40, 27); \ + ROL64(b41, b41, 20); \ + ROL64(b42, b42, 39); \ + ROL64(b43, b43, 8); \ + ROL64(b44, b44, 14); \ + } while (0) /* * The KHI macro integrates the "lane complement" optimization. On input, @@ -1055,466 +1102,505 @@ static const struct { * the input mask for the next round. */ -#define KHI_XO(d, a, b, c) do { \ - DECL64(kt); \ - OR64(kt, b, c); \ - XOR64(d, a, kt); \ - } while (0) - -#define KHI_XA(d, a, b, c) do { \ - DECL64(kt); \ - AND64(kt, b, c); \ - XOR64(d, a, kt); \ - } while (0) - -#define KHI(b00, b01, b02, b03, b04, b10, b11, b12, b13, b14, \ - b20, b21, b22, b23, b24, b30, b31, b32, b33, b34, \ - b40, b41, b42, b43, b44) \ - do { \ - DECL64(c0); \ - DECL64(c1); \ - DECL64(c2); \ - DECL64(c3); \ - DECL64(c4); \ - DECL64(bnn); \ - NOT64(bnn, b20); \ - KHI_XO(c0, b00, b10, b20); \ - KHI_XO(c1, b10, bnn, b30); \ - KHI_XA(c2, b20, b30, b40); \ - KHI_XO(c3, b30, b40, b00); \ - KHI_XA(c4, b40, b00, b10); \ - MOV64(b00, c0); \ - MOV64(b10, c1); \ - MOV64(b20, c2); \ - MOV64(b30, c3); \ - MOV64(b40, c4); \ - NOT64(bnn, b41); \ - KHI_XO(c0, b01, b11, b21); \ - KHI_XA(c1, b11, b21, b31); \ - KHI_XO(c2, b21, b31, bnn); \ - KHI_XO(c3, b31, b41, b01); \ - KHI_XA(c4, b41, b01, b11); \ - MOV64(b01, c0); \ - MOV64(b11, c1); \ - MOV64(b21, c2); \ - MOV64(b31, c3); \ - MOV64(b41, c4); \ - NOT64(bnn, b32); \ - KHI_XO(c0, b02, b12, b22); \ - KHI_XA(c1, b12, b22, b32); \ - KHI_XA(c2, b22, bnn, b42); \ - KHI_XO(c3, bnn, b42, b02); \ - KHI_XA(c4, b42, b02, b12); \ - MOV64(b02, c0); \ - MOV64(b12, c1); \ - MOV64(b22, c2); \ - MOV64(b32, c3); \ - MOV64(b42, c4); \ - NOT64(bnn, b33); \ - KHI_XA(c0, b03, b13, b23); \ - KHI_XO(c1, b13, b23, b33); \ - KHI_XO(c2, b23, bnn, b43); \ - KHI_XA(c3, bnn, b43, b03); \ - KHI_XO(c4, b43, b03, b13); \ - MOV64(b03, c0); \ - MOV64(b13, c1); \ - MOV64(b23, c2); \ - MOV64(b33, c3); \ - MOV64(b43, c4); \ - NOT64(bnn, b14); \ - KHI_XA(c0, b04, bnn, b24); \ - KHI_XO(c1, bnn, b24, b34); \ - KHI_XA(c2, b24, b34, b44); \ - KHI_XO(c3, b34, b44, b04); \ - KHI_XA(c4, b44, b04, b14); \ - MOV64(b04, c0); \ - MOV64(b14, c1); \ - MOV64(b24, c2); \ - MOV64(b34, c3); \ - MOV64(b44, c4); \ - } while (0) - -#define IOTA(r) XOR64_IOTA(a00, a00, r) - -#define P0 a00, a01, a02, a03, a04, a10, a11, a12, a13, a14, a20, a21, \ - a22, a23, a24, a30, a31, a32, a33, a34, a40, a41, a42, a43, a44 -#define P1 a00, a30, a10, a40, a20, a11, a41, a21, a01, a31, a22, a02, \ - a32, a12, a42, a33, a13, a43, a23, a03, a44, a24, a04, a34, a14 -#define P2 a00, a33, a11, a44, a22, a41, a24, a02, a30, a13, a32, a10, \ - a43, a21, a04, a23, a01, a34, a12, a40, a14, a42, a20, a03, a31 -#define P3 a00, a23, a41, a14, a32, a24, a42, a10, a33, a01, a43, a11, \ - a34, a02, a20, a12, a30, a03, a21, a44, a31, a04, a22, a40, a13 -#define P4 a00, a12, a24, a31, a43, a42, a04, a11, a23, a30, a34, a41, \ - a03, a10, a22, a21, a33, a40, a02, a14, a13, a20, a32, a44, a01 -#define P5 a00, a21, a42, a13, a34, a04, a20, a41, a12, a33, a03, a24, \ - a40, a11, a32, a02, a23, a44, a10, a31, a01, a22, a43, a14, a30 -#define P6 a00, a02, a04, a01, a03, a20, a22, a24, a21, a23, a40, a42, \ - a44, a41, a43, a10, a12, a14, a11, a13, a30, a32, a34, a31, a33 -#define P7 a00, a10, a20, a30, a40, a22, a32, a42, a02, a12, a44, a04, \ - a14, a24, a34, a11, a21, a31, a41, a01, a33, a43, a03, a13, a23 -#define P8 a00, a11, a22, a33, a44, a32, a43, a04, a10, a21, a14, a20, \ - a31, a42, a03, a41, a02, a13, a24, a30, a23, a34, a40, a01, a12 -#define P9 a00, a41, a32, a23, a14, a43, a34, a20, a11, a02, a31, a22, \ - a13, a04, a40, a24, a10, a01, a42, a33, a12, a03, a44, a30, a21 -#define P10 a00, a24, a43, a12, a31, a34, a03, a22, a41, a10, a13, a32, \ - a01, a20, a44, a42, a11, a30, a04, a23, a21, a40, a14, a33, a02 -#define P11 a00, a42, a34, a21, a13, a03, a40, a32, a24, a11, a01, a43, \ - a30, a22, a14, a04, a41, a33, a20, a12, a02, a44, a31, a23, a10 -#define P12 a00, a04, a03, a02, a01, a40, a44, a43, a42, a41, a30, a34, \ - a33, a32, a31, a20, a24, a23, a22, a21, a10, a14, a13, a12, a11 -#define P13 a00, a20, a40, a10, a30, a44, a14, a34, a04, a24, a33, a03, \ - a23, a43, a13, a22, a42, a12, a32, a02, a11, a31, a01, a21, a41 -#define P14 a00, a22, a44, a11, a33, a14, a31, a03, a20, a42, a23, a40, \ - a12, a34, a01, a32, a04, a21, a43, a10, a41, a13, a30, a02, a24 -#define P15 a00, a32, a14, a41, a23, a31, a13, a40, a22, a04, a12, a44, \ - a21, a03, a30, a43, a20, a02, a34, a11, a24, a01, a33, a10, a42 -#define P16 a00, a43, a31, a24, a12, a13, a01, a44, a32, a20, a21, a14, \ - a02, a40, a33, a34, a22, a10, a03, a41, a42, a30, a23, a11, a04 -#define P17 a00, a34, a13, a42, a21, a01, a30, a14, a43, a22, a02, a31, \ - a10, a44, a23, a03, a32, a11, a40, a24, a04, a33, a12, a41, a20 -#define P18 a00, a03, a01, a04, a02, a30, a33, a31, a34, a32, a10, a13, \ - a11, a14, a12, a40, a43, a41, a44, a42, a20, a23, a21, a24, a22 -#define P19 a00, a40, a30, a20, a10, a33, a23, a13, a03, a43, a11, a01, \ - a41, a31, a21, a44, a34, a24, a14, a04, a22, a12, a02, a42, a32 -#define P20 a00, a44, a33, a22, a11, a23, a12, a01, a40, a34, a41, a30, \ - a24, a13, a02, a14, a03, a42, a31, a20, a32, a21, a10, a04, a43 -#define P21 a00, a14, a23, a32, a41, a12, a21, a30, a44, a03, a24, a33, \ - a42, a01, a10, a31, a40, a04, a13, a22, a43, a02, a11, a20, a34 -#define P22 a00, a31, a12, a43, a24, a21, a02, a33, a14, a40, a42, a23, \ - a04, a30, a11, a13, a44, a20, a01, a32, a34, a10, a41, a22, a03 -#define P23 a00, a13, a21, a34, a42, a02, a10, a23, a31, a44, a04, a12, \ - a20, a33, a41, a01, a14, a22, a30, a43, a03, a11, a24, a32, a40 - -#define P1_TO_P0 do { \ - DECL64(t); \ - MOV64(t, a01); \ - MOV64(a01, a30); \ - MOV64(a30, a33); \ - MOV64(a33, a23); \ - MOV64(a23, a12); \ - MOV64(a12, a21); \ - MOV64(a21, a02); \ - MOV64(a02, a10); \ - MOV64(a10, a11); \ - MOV64(a11, a41); \ - MOV64(a41, a24); \ - MOV64(a24, a42); \ - MOV64(a42, a04); \ - MOV64(a04, a20); \ - MOV64(a20, a22); \ - MOV64(a22, a32); \ - MOV64(a32, a43); \ - MOV64(a43, a34); \ - MOV64(a34, a03); \ - MOV64(a03, a40); \ - MOV64(a40, a44); \ - MOV64(a44, a14); \ - MOV64(a14, a31); \ - MOV64(a31, a13); \ - MOV64(a13, t); \ - } while (0) - -#define P2_TO_P0 do { \ - DECL64(t); \ - MOV64(t, a01); \ - MOV64(a01, a33); \ - MOV64(a33, a12); \ - MOV64(a12, a02); \ - MOV64(a02, a11); \ - MOV64(a11, a24); \ - MOV64(a24, a04); \ - MOV64(a04, a22); \ - MOV64(a22, a43); \ - MOV64(a43, a03); \ - MOV64(a03, a44); \ - MOV64(a44, a31); \ - MOV64(a31, t); \ - MOV64(t, a10); \ - MOV64(a10, a41); \ - MOV64(a41, a42); \ - MOV64(a42, a20); \ - MOV64(a20, a32); \ - MOV64(a32, a34); \ - MOV64(a34, a40); \ - MOV64(a40, a14); \ - MOV64(a14, a13); \ - MOV64(a13, a30); \ - MOV64(a30, a23); \ - MOV64(a23, a21); \ - MOV64(a21, t); \ - } while (0) - -#define P4_TO_P0 do { \ - DECL64(t); \ - MOV64(t, a01); \ - MOV64(a01, a12); \ - MOV64(a12, a11); \ - MOV64(a11, a04); \ - MOV64(a04, a43); \ - MOV64(a43, a44); \ - MOV64(a44, t); \ - MOV64(t, a02); \ - MOV64(a02, a24); \ - MOV64(a24, a22); \ - MOV64(a22, a03); \ - MOV64(a03, a31); \ - MOV64(a31, a33); \ - MOV64(a33, t); \ - MOV64(t, a10); \ - MOV64(a10, a42); \ - MOV64(a42, a32); \ - MOV64(a32, a40); \ - MOV64(a40, a13); \ - MOV64(a13, a23); \ - MOV64(a23, t); \ - MOV64(t, a14); \ - MOV64(a14, a30); \ - MOV64(a30, a21); \ - MOV64(a21, a41); \ - MOV64(a41, a20); \ - MOV64(a20, a34); \ - MOV64(a34, t); \ - } while (0) - -#define P6_TO_P0 do { \ - DECL64(t); \ - MOV64(t, a01); \ - MOV64(a01, a02); \ - MOV64(a02, a04); \ - MOV64(a04, a03); \ - MOV64(a03, t); \ - MOV64(t, a10); \ - MOV64(a10, a20); \ - MOV64(a20, a40); \ - MOV64(a40, a30); \ - MOV64(a30, t); \ - MOV64(t, a11); \ - MOV64(a11, a22); \ - MOV64(a22, a44); \ - MOV64(a44, a33); \ - MOV64(a33, t); \ - MOV64(t, a12); \ - MOV64(a12, a24); \ - MOV64(a24, a43); \ - MOV64(a43, a31); \ - MOV64(a31, t); \ - MOV64(t, a13); \ - MOV64(a13, a21); \ - MOV64(a21, a42); \ - MOV64(a42, a34); \ - MOV64(a34, t); \ - MOV64(t, a14); \ - MOV64(a14, a23); \ - MOV64(a23, a41); \ - MOV64(a41, a32); \ - MOV64(a32, t); \ - } while (0) - -#define P8_TO_P0 do { \ - DECL64(t); \ - MOV64(t, a01); \ - MOV64(a01, a11); \ - MOV64(a11, a43); \ - MOV64(a43, t); \ - MOV64(t, a02); \ - MOV64(a02, a22); \ - MOV64(a22, a31); \ - MOV64(a31, t); \ - MOV64(t, a03); \ - MOV64(a03, a33); \ - MOV64(a33, a24); \ - MOV64(a24, t); \ - MOV64(t, a04); \ - MOV64(a04, a44); \ - MOV64(a44, a12); \ - MOV64(a12, t); \ - MOV64(t, a10); \ - MOV64(a10, a32); \ - MOV64(a32, a13); \ - MOV64(a13, t); \ - MOV64(t, a14); \ - MOV64(a14, a21); \ - MOV64(a21, a20); \ - MOV64(a20, t); \ - MOV64(t, a23); \ - MOV64(a23, a42); \ - MOV64(a42, a40); \ - MOV64(a40, t); \ - MOV64(t, a30); \ - MOV64(a30, a41); \ - MOV64(a41, a34); \ - MOV64(a34, t); \ - } while (0) - -#define P12_TO_P0 do { \ - DECL64(t); \ - MOV64(t, a01); \ - MOV64(a01, a04); \ - MOV64(a04, t); \ - MOV64(t, a02); \ - MOV64(a02, a03); \ - MOV64(a03, t); \ - MOV64(t, a10); \ - MOV64(a10, a40); \ - MOV64(a40, t); \ - MOV64(t, a11); \ - MOV64(a11, a44); \ - MOV64(a44, t); \ - MOV64(t, a12); \ - MOV64(a12, a43); \ - MOV64(a43, t); \ - MOV64(t, a13); \ - MOV64(a13, a42); \ - MOV64(a42, t); \ - MOV64(t, a14); \ - MOV64(a14, a41); \ - MOV64(a41, t); \ - MOV64(t, a20); \ - MOV64(a20, a30); \ - MOV64(a30, t); \ - MOV64(t, a21); \ - MOV64(a21, a34); \ - MOV64(a34, t); \ - MOV64(t, a22); \ - MOV64(a22, a33); \ - MOV64(a33, t); \ - MOV64(t, a23); \ - MOV64(a23, a32); \ - MOV64(a32, t); \ - MOV64(t, a24); \ - MOV64(a24, a31); \ - MOV64(a31, t); \ - } while (0) +#define KHI_XO(d, a, b, c) \ + do { \ + DECL64(kt); \ + OR64(kt, b, c); \ + XOR64(d, a, kt); \ + } while (0) + +#define KHI_XA(d, a, b, c) \ + do { \ + DECL64(kt); \ + AND64(kt, b, c); \ + XOR64(d, a, kt); \ + } while (0) + +#define KHI(b00, b01, b02, b03, b04, b10, b11, b12, b13, b14, b20, b21, b22, \ + b23, b24, b30, b31, b32, b33, b34, b40, b41, b42, b43, b44) \ + do { \ + DECL64(c0); \ + DECL64(c1); \ + DECL64(c2); \ + DECL64(c3); \ + DECL64(c4); \ + DECL64(bnn); \ + NOT64(bnn, b20); \ + KHI_XO(c0, b00, b10, b20); \ + KHI_XO(c1, b10, bnn, b30); \ + KHI_XA(c2, b20, b30, b40); \ + KHI_XO(c3, b30, b40, b00); \ + KHI_XA(c4, b40, b00, b10); \ + MOV64(b00, c0); \ + MOV64(b10, c1); \ + MOV64(b20, c2); \ + MOV64(b30, c3); \ + MOV64(b40, c4); \ + NOT64(bnn, b41); \ + KHI_XO(c0, b01, b11, b21); \ + KHI_XA(c1, b11, b21, b31); \ + KHI_XO(c2, b21, b31, bnn); \ + KHI_XO(c3, b31, b41, b01); \ + KHI_XA(c4, b41, b01, b11); \ + MOV64(b01, c0); \ + MOV64(b11, c1); \ + MOV64(b21, c2); \ + MOV64(b31, c3); \ + MOV64(b41, c4); \ + NOT64(bnn, b32); \ + KHI_XO(c0, b02, b12, b22); \ + KHI_XA(c1, b12, b22, b32); \ + KHI_XA(c2, b22, bnn, b42); \ + KHI_XO(c3, bnn, b42, b02); \ + KHI_XA(c4, b42, b02, b12); \ + MOV64(b02, c0); \ + MOV64(b12, c1); \ + MOV64(b22, c2); \ + MOV64(b32, c3); \ + MOV64(b42, c4); \ + NOT64(bnn, b33); \ + KHI_XA(c0, b03, b13, b23); \ + KHI_XO(c1, b13, b23, b33); \ + KHI_XO(c2, b23, bnn, b43); \ + KHI_XA(c3, bnn, b43, b03); \ + KHI_XO(c4, b43, b03, b13); \ + MOV64(b03, c0); \ + MOV64(b13, c1); \ + MOV64(b23, c2); \ + MOV64(b33, c3); \ + MOV64(b43, c4); \ + NOT64(bnn, b14); \ + KHI_XA(c0, b04, bnn, b24); \ + KHI_XO(c1, bnn, b24, b34); \ + KHI_XA(c2, b24, b34, b44); \ + KHI_XO(c3, b34, b44, b04); \ + KHI_XA(c4, b44, b04, b14); \ + MOV64(b04, c0); \ + MOV64(b14, c1); \ + MOV64(b24, c2); \ + MOV64(b34, c3); \ + MOV64(b44, c4); \ + } while (0) + +#define IOTA(r) XOR64_IOTA(a00, a00, r) + +#define P0 \ + a00, a01, a02, a03, a04, a10, a11, a12, a13, a14, a20, a21, a22, a23, a24, \ + a30, a31, a32, a33, a34, a40, a41, a42, a43, a44 +#define P1 \ + a00, a30, a10, a40, a20, a11, a41, a21, a01, a31, a22, a02, a32, a12, a42, \ + a33, a13, a43, a23, a03, a44, a24, a04, a34, a14 +#define P2 \ + a00, a33, a11, a44, a22, a41, a24, a02, a30, a13, a32, a10, a43, a21, a04, \ + a23, a01, a34, a12, a40, a14, a42, a20, a03, a31 +#define P3 \ + a00, a23, a41, a14, a32, a24, a42, a10, a33, a01, a43, a11, a34, a02, a20, \ + a12, a30, a03, a21, a44, a31, a04, a22, a40, a13 +#define P4 \ + a00, a12, a24, a31, a43, a42, a04, a11, a23, a30, a34, a41, a03, a10, a22, \ + a21, a33, a40, a02, a14, a13, a20, a32, a44, a01 +#define P5 \ + a00, a21, a42, a13, a34, a04, a20, a41, a12, a33, a03, a24, a40, a11, a32, \ + a02, a23, a44, a10, a31, a01, a22, a43, a14, a30 +#define P6 \ + a00, a02, a04, a01, a03, a20, a22, a24, a21, a23, a40, a42, a44, a41, a43, \ + a10, a12, a14, a11, a13, a30, a32, a34, a31, a33 +#define P7 \ + a00, a10, a20, a30, a40, a22, a32, a42, a02, a12, a44, a04, a14, a24, a34, \ + a11, a21, a31, a41, a01, a33, a43, a03, a13, a23 +#define P8 \ + a00, a11, a22, a33, a44, a32, a43, a04, a10, a21, a14, a20, a31, a42, a03, \ + a41, a02, a13, a24, a30, a23, a34, a40, a01, a12 +#define P9 \ + a00, a41, a32, a23, a14, a43, a34, a20, a11, a02, a31, a22, a13, a04, a40, \ + a24, a10, a01, a42, a33, a12, a03, a44, a30, a21 +#define P10 \ + a00, a24, a43, a12, a31, a34, a03, a22, a41, a10, a13, a32, a01, a20, a44, \ + a42, a11, a30, a04, a23, a21, a40, a14, a33, a02 +#define P11 \ + a00, a42, a34, a21, a13, a03, a40, a32, a24, a11, a01, a43, a30, a22, a14, \ + a04, a41, a33, a20, a12, a02, a44, a31, a23, a10 +#define P12 \ + a00, a04, a03, a02, a01, a40, a44, a43, a42, a41, a30, a34, a33, a32, a31, \ + a20, a24, a23, a22, a21, a10, a14, a13, a12, a11 +#define P13 \ + a00, a20, a40, a10, a30, a44, a14, a34, a04, a24, a33, a03, a23, a43, a13, \ + a22, a42, a12, a32, a02, a11, a31, a01, a21, a41 +#define P14 \ + a00, a22, a44, a11, a33, a14, a31, a03, a20, a42, a23, a40, a12, a34, a01, \ + a32, a04, a21, a43, a10, a41, a13, a30, a02, a24 +#define P15 \ + a00, a32, a14, a41, a23, a31, a13, a40, a22, a04, a12, a44, a21, a03, a30, \ + a43, a20, a02, a34, a11, a24, a01, a33, a10, a42 +#define P16 \ + a00, a43, a31, a24, a12, a13, a01, a44, a32, a20, a21, a14, a02, a40, a33, \ + a34, a22, a10, a03, a41, a42, a30, a23, a11, a04 +#define P17 \ + a00, a34, a13, a42, a21, a01, a30, a14, a43, a22, a02, a31, a10, a44, a23, \ + a03, a32, a11, a40, a24, a04, a33, a12, a41, a20 +#define P18 \ + a00, a03, a01, a04, a02, a30, a33, a31, a34, a32, a10, a13, a11, a14, a12, \ + a40, a43, a41, a44, a42, a20, a23, a21, a24, a22 +#define P19 \ + a00, a40, a30, a20, a10, a33, a23, a13, a03, a43, a11, a01, a41, a31, a21, \ + a44, a34, a24, a14, a04, a22, a12, a02, a42, a32 +#define P20 \ + a00, a44, a33, a22, a11, a23, a12, a01, a40, a34, a41, a30, a24, a13, a02, \ + a14, a03, a42, a31, a20, a32, a21, a10, a04, a43 +#define P21 \ + a00, a14, a23, a32, a41, a12, a21, a30, a44, a03, a24, a33, a42, a01, a10, \ + a31, a40, a04, a13, a22, a43, a02, a11, a20, a34 +#define P22 \ + a00, a31, a12, a43, a24, a21, a02, a33, a14, a40, a42, a23, a04, a30, a11, \ + a13, a44, a20, a01, a32, a34, a10, a41, a22, a03 +#define P23 \ + a00, a13, a21, a34, a42, a02, a10, a23, a31, a44, a04, a12, a20, a33, a41, \ + a01, a14, a22, a30, a43, a03, a11, a24, a32, a40 + +#define P1_TO_P0 \ + do { \ + DECL64(t); \ + MOV64(t, a01); \ + MOV64(a01, a30); \ + MOV64(a30, a33); \ + MOV64(a33, a23); \ + MOV64(a23, a12); \ + MOV64(a12, a21); \ + MOV64(a21, a02); \ + MOV64(a02, a10); \ + MOV64(a10, a11); \ + MOV64(a11, a41); \ + MOV64(a41, a24); \ + MOV64(a24, a42); \ + MOV64(a42, a04); \ + MOV64(a04, a20); \ + MOV64(a20, a22); \ + MOV64(a22, a32); \ + MOV64(a32, a43); \ + MOV64(a43, a34); \ + MOV64(a34, a03); \ + MOV64(a03, a40); \ + MOV64(a40, a44); \ + MOV64(a44, a14); \ + MOV64(a14, a31); \ + MOV64(a31, a13); \ + MOV64(a13, t); \ + } while (0) + +#define P2_TO_P0 \ + do { \ + DECL64(t); \ + MOV64(t, a01); \ + MOV64(a01, a33); \ + MOV64(a33, a12); \ + MOV64(a12, a02); \ + MOV64(a02, a11); \ + MOV64(a11, a24); \ + MOV64(a24, a04); \ + MOV64(a04, a22); \ + MOV64(a22, a43); \ + MOV64(a43, a03); \ + MOV64(a03, a44); \ + MOV64(a44, a31); \ + MOV64(a31, t); \ + MOV64(t, a10); \ + MOV64(a10, a41); \ + MOV64(a41, a42); \ + MOV64(a42, a20); \ + MOV64(a20, a32); \ + MOV64(a32, a34); \ + MOV64(a34, a40); \ + MOV64(a40, a14); \ + MOV64(a14, a13); \ + MOV64(a13, a30); \ + MOV64(a30, a23); \ + MOV64(a23, a21); \ + MOV64(a21, t); \ + } while (0) + +#define P4_TO_P0 \ + do { \ + DECL64(t); \ + MOV64(t, a01); \ + MOV64(a01, a12); \ + MOV64(a12, a11); \ + MOV64(a11, a04); \ + MOV64(a04, a43); \ + MOV64(a43, a44); \ + MOV64(a44, t); \ + MOV64(t, a02); \ + MOV64(a02, a24); \ + MOV64(a24, a22); \ + MOV64(a22, a03); \ + MOV64(a03, a31); \ + MOV64(a31, a33); \ + MOV64(a33, t); \ + MOV64(t, a10); \ + MOV64(a10, a42); \ + MOV64(a42, a32); \ + MOV64(a32, a40); \ + MOV64(a40, a13); \ + MOV64(a13, a23); \ + MOV64(a23, t); \ + MOV64(t, a14); \ + MOV64(a14, a30); \ + MOV64(a30, a21); \ + MOV64(a21, a41); \ + MOV64(a41, a20); \ + MOV64(a20, a34); \ + MOV64(a34, t); \ + } while (0) + +#define P6_TO_P0 \ + do { \ + DECL64(t); \ + MOV64(t, a01); \ + MOV64(a01, a02); \ + MOV64(a02, a04); \ + MOV64(a04, a03); \ + MOV64(a03, t); \ + MOV64(t, a10); \ + MOV64(a10, a20); \ + MOV64(a20, a40); \ + MOV64(a40, a30); \ + MOV64(a30, t); \ + MOV64(t, a11); \ + MOV64(a11, a22); \ + MOV64(a22, a44); \ + MOV64(a44, a33); \ + MOV64(a33, t); \ + MOV64(t, a12); \ + MOV64(a12, a24); \ + MOV64(a24, a43); \ + MOV64(a43, a31); \ + MOV64(a31, t); \ + MOV64(t, a13); \ + MOV64(a13, a21); \ + MOV64(a21, a42); \ + MOV64(a42, a34); \ + MOV64(a34, t); \ + MOV64(t, a14); \ + MOV64(a14, a23); \ + MOV64(a23, a41); \ + MOV64(a41, a32); \ + MOV64(a32, t); \ + } while (0) + +#define P8_TO_P0 \ + do { \ + DECL64(t); \ + MOV64(t, a01); \ + MOV64(a01, a11); \ + MOV64(a11, a43); \ + MOV64(a43, t); \ + MOV64(t, a02); \ + MOV64(a02, a22); \ + MOV64(a22, a31); \ + MOV64(a31, t); \ + MOV64(t, a03); \ + MOV64(a03, a33); \ + MOV64(a33, a24); \ + MOV64(a24, t); \ + MOV64(t, a04); \ + MOV64(a04, a44); \ + MOV64(a44, a12); \ + MOV64(a12, t); \ + MOV64(t, a10); \ + MOV64(a10, a32); \ + MOV64(a32, a13); \ + MOV64(a13, t); \ + MOV64(t, a14); \ + MOV64(a14, a21); \ + MOV64(a21, a20); \ + MOV64(a20, t); \ + MOV64(t, a23); \ + MOV64(a23, a42); \ + MOV64(a42, a40); \ + MOV64(a40, t); \ + MOV64(t, a30); \ + MOV64(a30, a41); \ + MOV64(a41, a34); \ + MOV64(a34, t); \ + } while (0) + +#define P12_TO_P0 \ + do { \ + DECL64(t); \ + MOV64(t, a01); \ + MOV64(a01, a04); \ + MOV64(a04, t); \ + MOV64(t, a02); \ + MOV64(a02, a03); \ + MOV64(a03, t); \ + MOV64(t, a10); \ + MOV64(a10, a40); \ + MOV64(a40, t); \ + MOV64(t, a11); \ + MOV64(a11, a44); \ + MOV64(a44, t); \ + MOV64(t, a12); \ + MOV64(a12, a43); \ + MOV64(a43, t); \ + MOV64(t, a13); \ + MOV64(a13, a42); \ + MOV64(a42, t); \ + MOV64(t, a14); \ + MOV64(a14, a41); \ + MOV64(a41, t); \ + MOV64(t, a20); \ + MOV64(a20, a30); \ + MOV64(a30, t); \ + MOV64(t, a21); \ + MOV64(a21, a34); \ + MOV64(a34, t); \ + MOV64(t, a22); \ + MOV64(a22, a33); \ + MOV64(a33, t); \ + MOV64(t, a23); \ + MOV64(a23, a32); \ + MOV64(a32, t); \ + MOV64(t, a24); \ + MOV64(a24, a31); \ + MOV64(a31, t); \ + } while (0) #define LPAR ( #define RPAR ) -#define KF_ELT(r, s, k) do { \ - THETA LPAR P ## r RPAR; \ - RHO LPAR P ## r RPAR; \ - KHI LPAR P ## s RPAR; \ - IOTA(k); \ - } while (0) +#define KF_ELT(r, s, k) \ + do { \ + THETA LPAR P##r RPAR; \ + RHO LPAR P##r RPAR; \ + KHI LPAR P##s RPAR; \ + IOTA(k); \ + } while (0) -#define DO(x) x +#define DO(x) x -#define KECCAK_F_1600 DO(KECCAK_F_1600_) +#define KECCAK_F_1600 DO(KECCAK_F_1600_) #if SPH_KECCAK_UNROLL == 1 -#define KECCAK_F_1600_ do { \ - int j; \ - for (j = 0; j < 24; j ++) { \ - KF_ELT( 0, 1, RC[j + 0]); \ - P1_TO_P0; \ - } \ - } while (0) +#define KECCAK_F_1600_ \ + do { \ + int j; \ + for (j = 0; j < 24; j++) { \ + KF_ELT(0, 1, RC[j + 0]); \ + P1_TO_P0; \ + } \ + } while (0) #elif SPH_KECCAK_UNROLL == 2 -#define KECCAK_F_1600_ do { \ - int j; \ - for (j = 0; j < 24; j += 2) { \ - KF_ELT( 0, 1, RC[j + 0]); \ - KF_ELT( 1, 2, RC[j + 1]); \ - P2_TO_P0; \ - } \ - } while (0) +#define KECCAK_F_1600_ \ + do { \ + int j; \ + for (j = 0; j < 24; j += 2) { \ + KF_ELT(0, 1, RC[j + 0]); \ + KF_ELT(1, 2, RC[j + 1]); \ + P2_TO_P0; \ + } \ + } while (0) #elif SPH_KECCAK_UNROLL == 4 -#define KECCAK_F_1600_ do { \ - int j; \ - for (j = 0; j < 24; j += 4) { \ - KF_ELT( 0, 1, RC[j + 0]); \ - KF_ELT( 1, 2, RC[j + 1]); \ - KF_ELT( 2, 3, RC[j + 2]); \ - KF_ELT( 3, 4, RC[j + 3]); \ - P4_TO_P0; \ - } \ - } while (0) +#define KECCAK_F_1600_ \ + do { \ + int j; \ + for (j = 0; j < 24; j += 4) { \ + KF_ELT(0, 1, RC[j + 0]); \ + KF_ELT(1, 2, RC[j + 1]); \ + KF_ELT(2, 3, RC[j + 2]); \ + KF_ELT(3, 4, RC[j + 3]); \ + P4_TO_P0; \ + } \ + } while (0) #elif SPH_KECCAK_UNROLL == 6 -#define KECCAK_F_1600_ do { \ - int j; \ - for (j = 0; j < 24; j += 6) { \ - KF_ELT( 0, 1, RC[j + 0]); \ - KF_ELT( 1, 2, RC[j + 1]); \ - KF_ELT( 2, 3, RC[j + 2]); \ - KF_ELT( 3, 4, RC[j + 3]); \ - KF_ELT( 4, 5, RC[j + 4]); \ - KF_ELT( 5, 6, RC[j + 5]); \ - P6_TO_P0; \ - } \ - } while (0) +#define KECCAK_F_1600_ \ + do { \ + int j; \ + for (j = 0; j < 24; j += 6) { \ + KF_ELT(0, 1, RC[j + 0]); \ + KF_ELT(1, 2, RC[j + 1]); \ + KF_ELT(2, 3, RC[j + 2]); \ + KF_ELT(3, 4, RC[j + 3]); \ + KF_ELT(4, 5, RC[j + 4]); \ + KF_ELT(5, 6, RC[j + 5]); \ + P6_TO_P0; \ + } \ + } while (0) #elif SPH_KECCAK_UNROLL == 8 -#define KECCAK_F_1600_ do { \ - int j; \ - for (j = 0; j < 24; j += 8) { \ - KF_ELT( 0, 1, RC[j + 0]); \ - KF_ELT( 1, 2, RC[j + 1]); \ - KF_ELT( 2, 3, RC[j + 2]); \ - KF_ELT( 3, 4, RC[j + 3]); \ - KF_ELT( 4, 5, RC[j + 4]); \ - KF_ELT( 5, 6, RC[j + 5]); \ - KF_ELT( 6, 7, RC[j + 6]); \ - KF_ELT( 7, 8, RC[j + 7]); \ - P8_TO_P0; \ - } \ - } while (0) +#define KECCAK_F_1600_ \ + do { \ + int j; \ + for (j = 0; j < 24; j += 8) { \ + KF_ELT(0, 1, RC[j + 0]); \ + KF_ELT(1, 2, RC[j + 1]); \ + KF_ELT(2, 3, RC[j + 2]); \ + KF_ELT(3, 4, RC[j + 3]); \ + KF_ELT(4, 5, RC[j + 4]); \ + KF_ELT(5, 6, RC[j + 5]); \ + KF_ELT(6, 7, RC[j + 6]); \ + KF_ELT(7, 8, RC[j + 7]); \ + P8_TO_P0; \ + } \ + } while (0) #elif SPH_KECCAK_UNROLL == 12 -#define KECCAK_F_1600_ do { \ - int j; \ - for (j = 0; j < 24; j += 12) { \ - KF_ELT( 0, 1, RC[j + 0]); \ - KF_ELT( 1, 2, RC[j + 1]); \ - KF_ELT( 2, 3, RC[j + 2]); \ - KF_ELT( 3, 4, RC[j + 3]); \ - KF_ELT( 4, 5, RC[j + 4]); \ - KF_ELT( 5, 6, RC[j + 5]); \ - KF_ELT( 6, 7, RC[j + 6]); \ - KF_ELT( 7, 8, RC[j + 7]); \ - KF_ELT( 8, 9, RC[j + 8]); \ - KF_ELT( 9, 10, RC[j + 9]); \ - KF_ELT(10, 11, RC[j + 10]); \ - KF_ELT(11, 12, RC[j + 11]); \ - P12_TO_P0; \ - } \ - } while (0) +#define KECCAK_F_1600_ \ + do { \ + int j; \ + for (j = 0; j < 24; j += 12) { \ + KF_ELT(0, 1, RC[j + 0]); \ + KF_ELT(1, 2, RC[j + 1]); \ + KF_ELT(2, 3, RC[j + 2]); \ + KF_ELT(3, 4, RC[j + 3]); \ + KF_ELT(4, 5, RC[j + 4]); \ + KF_ELT(5, 6, RC[j + 5]); \ + KF_ELT(6, 7, RC[j + 6]); \ + KF_ELT(7, 8, RC[j + 7]); \ + KF_ELT(8, 9, RC[j + 8]); \ + KF_ELT(9, 10, RC[j + 9]); \ + KF_ELT(10, 11, RC[j + 10]); \ + KF_ELT(11, 12, RC[j + 11]); \ + P12_TO_P0; \ + } \ + } while (0) #elif SPH_KECCAK_UNROLL == 0 -#define KECCAK_F_1600_ do { \ - KF_ELT( 0, 1, RC[ 0]); \ - KF_ELT( 1, 2, RC[ 1]); \ - KF_ELT( 2, 3, RC[ 2]); \ - KF_ELT( 3, 4, RC[ 3]); \ - KF_ELT( 4, 5, RC[ 4]); \ - KF_ELT( 5, 6, RC[ 5]); \ - KF_ELT( 6, 7, RC[ 6]); \ - KF_ELT( 7, 8, RC[ 7]); \ - KF_ELT( 8, 9, RC[ 8]); \ - KF_ELT( 9, 10, RC[ 9]); \ - KF_ELT(10, 11, RC[10]); \ - KF_ELT(11, 12, RC[11]); \ - KF_ELT(12, 13, RC[12]); \ - KF_ELT(13, 14, RC[13]); \ - KF_ELT(14, 15, RC[14]); \ - KF_ELT(15, 16, RC[15]); \ - KF_ELT(16, 17, RC[16]); \ - KF_ELT(17, 18, RC[17]); \ - KF_ELT(18, 19, RC[18]); \ - KF_ELT(19, 20, RC[19]); \ - KF_ELT(20, 21, RC[20]); \ - KF_ELT(21, 22, RC[21]); \ - KF_ELT(22, 23, RC[22]); \ - KF_ELT(23, 0, RC[23]); \ - } while (0) +#define KECCAK_F_1600_ \ + do { \ + KF_ELT(0, 1, RC[0]); \ + KF_ELT(1, 2, RC[1]); \ + KF_ELT(2, 3, RC[2]); \ + KF_ELT(3, 4, RC[3]); \ + KF_ELT(4, 5, RC[4]); \ + KF_ELT(5, 6, RC[5]); \ + KF_ELT(6, 7, RC[6]); \ + KF_ELT(7, 8, RC[7]); \ + KF_ELT(8, 9, RC[8]); \ + KF_ELT(9, 10, RC[9]); \ + KF_ELT(10, 11, RC[10]); \ + KF_ELT(11, 12, RC[11]); \ + KF_ELT(12, 13, RC[12]); \ + KF_ELT(13, 14, RC[13]); \ + KF_ELT(14, 15, RC[14]); \ + KF_ELT(15, 16, RC[15]); \ + KF_ELT(16, 17, RC[16]); \ + KF_ELT(17, 18, RC[17]); \ + KF_ELT(18, 19, RC[18]); \ + KF_ELT(19, 20, RC[19]); \ + KF_ELT(20, 21, RC[20]); \ + KF_ELT(21, 22, RC[21]); \ + KF_ELT(22, 23, RC[22]); \ + KF_ELT(23, 0, RC[23]); \ + } while (0) #else @@ -1522,273 +1608,177 @@ static const struct { #endif -static void -keccak_init(sph_keccak_context *kc, unsigned out_size) -{ - int i; +static void keccak_init(sph_keccak_context *kc, unsigned out_size) { + int i; #if SPH_KECCAK_64 - for (i = 0; i < 25; i ++) - kc->u.wide[i] = 0; - /* - * Initialization for the "lane complement". - */ - kc->u.wide[ 1] = SPH_C64(0xFFFFFFFFFFFFFFFF); - kc->u.wide[ 2] = SPH_C64(0xFFFFFFFFFFFFFFFF); - kc->u.wide[ 8] = SPH_C64(0xFFFFFFFFFFFFFFFF); - kc->u.wide[12] = SPH_C64(0xFFFFFFFFFFFFFFFF); - kc->u.wide[17] = SPH_C64(0xFFFFFFFFFFFFFFFF); - kc->u.wide[20] = SPH_C64(0xFFFFFFFFFFFFFFFF); + for (i = 0; i < 25; i++) + kc->u.wide[i] = 0; + /* + * Initialization for the "lane complement". + */ + kc->u.wide[1] = SPH_C64(0xFFFFFFFFFFFFFFFF); + kc->u.wide[2] = SPH_C64(0xFFFFFFFFFFFFFFFF); + kc->u.wide[8] = SPH_C64(0xFFFFFFFFFFFFFFFF); + kc->u.wide[12] = SPH_C64(0xFFFFFFFFFFFFFFFF); + kc->u.wide[17] = SPH_C64(0xFFFFFFFFFFFFFFFF); + kc->u.wide[20] = SPH_C64(0xFFFFFFFFFFFFFFFF); #else - for (i = 0; i < 50; i ++) - kc->u.narrow[i] = 0; - /* - * Initialization for the "lane complement". - * Note: since we set to all-one full 64-bit words, - * interleaving (if applicable) is a no-op. - */ - kc->u.narrow[ 2] = SPH_C32(0xFFFFFFFF); - kc->u.narrow[ 3] = SPH_C32(0xFFFFFFFF); - kc->u.narrow[ 4] = SPH_C32(0xFFFFFFFF); - kc->u.narrow[ 5] = SPH_C32(0xFFFFFFFF); - kc->u.narrow[16] = SPH_C32(0xFFFFFFFF); - kc->u.narrow[17] = SPH_C32(0xFFFFFFFF); - kc->u.narrow[24] = SPH_C32(0xFFFFFFFF); - kc->u.narrow[25] = SPH_C32(0xFFFFFFFF); - kc->u.narrow[34] = SPH_C32(0xFFFFFFFF); - kc->u.narrow[35] = SPH_C32(0xFFFFFFFF); - kc->u.narrow[40] = SPH_C32(0xFFFFFFFF); - kc->u.narrow[41] = SPH_C32(0xFFFFFFFF); + for (i = 0; i < 50; i++) + kc->u.narrow[i] = 0; + /* + * Initialization for the "lane complement". + * Note: since we set to all-one full 64-bit words, + * interleaving (if applicable) is a no-op. + */ + kc->u.narrow[2] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[3] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[4] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[5] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[16] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[17] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[24] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[25] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[34] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[35] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[40] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[41] = SPH_C32(0xFFFFFFFF); #endif - kc->ptr = 0; - kc->lim = 200 - (out_size >> 2); + kc->ptr = 0; + kc->lim = 200 - (out_size >> 2); } -static void -keccak_core(sph_keccak_context *kc, const void *data, size_t len, size_t lim) -{ - unsigned char *buf; - size_t ptr; - DECL_STATE - - buf = kc->buf; - ptr = kc->ptr; - - if (len < (lim - ptr)) { - memcpy(buf + ptr, data, len); - kc->ptr = ptr + len; - return; - } - - READ_STATE(kc); - while (len > 0) { - size_t clen; - - clen = (lim - ptr); - if (clen > len) - clen = len; - memcpy(buf + ptr, data, clen); - ptr += clen; - data = (const unsigned char *)data + clen; - len -= clen; - if (ptr == lim) { - INPUT_BUF(lim); - KECCAK_F_1600; - ptr = 0; - } - } - WRITE_STATE(kc); - kc->ptr = ptr; +static void keccak_core(sph_keccak_context *kc, const void *data, size_t len, + size_t lim) { + unsigned char *buf; + size_t ptr; + DECL_STATE + + buf = kc->buf; + ptr = kc->ptr; + + if (len < (lim - ptr)) { + memcpy(buf + ptr, data, len); + kc->ptr = ptr + len; + return; + } + + READ_STATE(kc); + while (len > 0) { + size_t clen; + + clen = (lim - ptr); + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == lim) { + INPUT_BUF(lim); + KECCAK_F_1600; + ptr = 0; + } + } + WRITE_STATE(kc); + kc->ptr = ptr; } #if SPH_KECCAK_64 -#define DEFCLOSE(d, lim) \ - static void keccak_close ## d( \ - sph_keccak_context *kc, unsigned ub, unsigned n, void *dst) \ - { \ - unsigned eb; \ - union { \ - unsigned char tmp[lim + 1]; \ - sph_u64 dummy; /* for alignment */ \ - } u; \ - size_t j; \ - \ - eb = (0x100 | (ub & 0xFF)) >> (8 - n); \ - if (kc->ptr == (lim - 1)) { \ - if (n == 7) { \ - u.tmp[0] = eb; \ - memset(u.tmp + 1, 0, lim - 1); \ - u.tmp[lim] = 0x80; \ - j = 1 + lim; \ - } else { \ - u.tmp[0] = eb | 0x80; \ - j = 1; \ - } \ - } else { \ - j = lim - kc->ptr; \ - u.tmp[0] = eb; \ - memset(u.tmp + 1, 0, j - 2); \ - u.tmp[j - 1] = 0x80; \ - } \ - keccak_core(kc, u.tmp, j, lim); \ - /* Finalize the "lane complement" */ \ - kc->u.wide[ 1] = ~kc->u.wide[ 1]; \ - kc->u.wide[ 2] = ~kc->u.wide[ 2]; \ - kc->u.wide[ 8] = ~kc->u.wide[ 8]; \ - kc->u.wide[12] = ~kc->u.wide[12]; \ - kc->u.wide[17] = ~kc->u.wide[17]; \ - kc->u.wide[20] = ~kc->u.wide[20]; \ - for (j = 0; j < d; j += 8) \ - sph_enc64le_aligned(u.tmp + j, kc->u.wide[j >> 3]); \ - memcpy(dst, u.tmp, d); \ - keccak_init(kc, (unsigned)d << 3); \ - } \ -\ - static void flex_keccak_close ## d( \ - sph_keccak_context *kc, unsigned ub, unsigned n, void *dst) \ - { \ - unsigned eb; \ - union { \ - unsigned char tmp[lim + 1]; \ - sph_u64 dummy; /* for alignment */ \ - } u; \ - size_t j; \ - \ - eb = 6; \ - if (kc->ptr == (lim - 1)) { \ - if (n == 7) { \ - u.tmp[0] = eb; \ - memset(u.tmp + 1, 0, lim - 1); \ - u.tmp[lim] = 0x80; \ - j = 1 + lim; \ - } else { \ - u.tmp[0] = eb | 0x80; \ - j = 1; \ - } \ - } else { \ - j = lim - kc->ptr; \ - u.tmp[0] = eb; \ - memset(u.tmp + 1, 0, j - 2); \ - u.tmp[j - 1] = 0x80; \ - } \ - keccak_core(kc, u.tmp, j, lim); \ - /* Finalize the "lane complement" */ \ - kc->u.wide[ 1] = ~kc->u.wide[ 1]; \ - kc->u.wide[ 2] = ~kc->u.wide[ 2]; \ - kc->u.wide[ 8] = ~kc->u.wide[ 8]; \ - kc->u.wide[12] = ~kc->u.wide[12]; \ - kc->u.wide[17] = ~kc->u.wide[17]; \ - kc->u.wide[20] = ~kc->u.wide[20]; \ - for (j = 0; j < d; j += 8) \ - sph_enc64le_aligned(u.tmp + j, kc->u.wide[j >> 3]); \ - memcpy(dst, u.tmp, d); \ - keccak_init(kc, (unsigned)d << 3); \ - } \ +#define DEFCLOSE(d, lim) \ + static void keccak_close##d(sph_keccak_context *kc, \ + unsigned ub, unsigned n, \ + void *dst) { \ + unsigned eb; \ + union { \ + unsigned char tmp[lim + 1]; \ + sph_u64 dummy; /* for alignment */ \ + } u; \ + size_t j; \ + \ + eb = hard_coded_eb; \ + if (kc->ptr == (lim - 1)) { \ + if (n == 7) { \ + u.tmp[0] = eb; \ + memset(u.tmp + 1, 0, lim - 1); \ + u.tmp[lim] = 0x80; \ + j = 1 + lim; \ + } else { \ + u.tmp[0] = eb | 0x80; \ + j = 1; \ + } \ + } else { \ + j = lim - kc->ptr; \ + u.tmp[0] = eb; \ + memset(u.tmp + 1, 0, j - 2); \ + u.tmp[j - 1] = 0x80; \ + } \ + keccak_core(kc, u.tmp, j, lim); \ + /* Finalize the "lane complement" */ \ + kc->u.wide[1] = ~kc->u.wide[1]; \ + kc->u.wide[2] = ~kc->u.wide[2]; \ + kc->u.wide[8] = ~kc->u.wide[8]; \ + kc->u.wide[12] = ~kc->u.wide[12]; \ + kc->u.wide[17] = ~kc->u.wide[17]; \ + kc->u.wide[20] = ~kc->u.wide[20]; \ + for (j = 0; j < d; j += 8) \ + sph_enc64le_aligned(u.tmp + j, kc->u.wide[j >> 3]); \ + memcpy(dst, u.tmp, d); \ + } #else -#define DEFCLOSE(d, lim) \ - static void keccak_close ## d( \ - sph_keccak_context *kc, unsigned ub, unsigned n, void *dst) \ - { \ - unsigned eb; \ - union { \ - unsigned char tmp[lim + 1]; \ - sph_u64 dummy; /* for alignment */ \ - } u; \ - size_t j; \ - \ - eb = (0x100 | (ub & 0xFF)) >> (8 - n); \ - if (kc->ptr == (lim - 1)) { \ - if (n == 7) { \ - u.tmp[0] = eb; \ - memset(u.tmp + 1, 0, lim - 1); \ - u.tmp[lim] = 0x80; \ - j = 1 + lim; \ - } else { \ - u.tmp[0] = eb | 0x80; \ - j = 1; \ - } \ - } else { \ - j = lim - kc->ptr; \ - u.tmp[0] = eb; \ - memset(u.tmp + 1, 0, j - 2); \ - u.tmp[j - 1] = 0x80; \ - } \ - keccak_core(kc, u.tmp, j, lim); \ - /* Finalize the "lane complement" */ \ - kc->u.narrow[ 2] = ~kc->u.narrow[ 2]; \ - kc->u.narrow[ 3] = ~kc->u.narrow[ 3]; \ - kc->u.narrow[ 4] = ~kc->u.narrow[ 4]; \ - kc->u.narrow[ 5] = ~kc->u.narrow[ 5]; \ - kc->u.narrow[16] = ~kc->u.narrow[16]; \ - kc->u.narrow[17] = ~kc->u.narrow[17]; \ - kc->u.narrow[24] = ~kc->u.narrow[24]; \ - kc->u.narrow[25] = ~kc->u.narrow[25]; \ - kc->u.narrow[34] = ~kc->u.narrow[34]; \ - kc->u.narrow[35] = ~kc->u.narrow[35]; \ - kc->u.narrow[40] = ~kc->u.narrow[40]; \ - kc->u.narrow[41] = ~kc->u.narrow[41]; \ - /* un-interleave */ \ - for (j = 0; j < 50; j += 2) \ - UNINTERLEAVE(kc->u.narrow[j], kc->u.narrow[j + 1]); \ - for (j = 0; j < d; j += 4) \ - sph_enc32le_aligned(u.tmp + j, kc->u.narrow[j >> 2]); \ - memcpy(dst, u.tmp, d); \ - keccak_init(kc, (unsigned)d << 3); \ - } \ -\ - static void flex_keccak_close ## d( \ - sph_keccak_context *kc, unsigned ub, unsigned n, void *dst) \ - { \ - unsigned eb; \ - union { \ - unsigned char tmp[lim + 1]; \ - sph_u64 dummy; /* for alignment */ \ - } u; \ - size_t j; \ - \ - eb = 6; \ - if (kc->ptr == (lim - 1)) { \ - if (n == 7) { \ - u.tmp[0] = eb; \ - memset(u.tmp + 1, 0, lim - 1); \ - u.tmp[lim] = 0x80; \ - j = 1 + lim; \ - } else { \ - u.tmp[0] = eb | 0x80; \ - j = 1; \ - } \ - } else { \ - j = lim - kc->ptr; \ - u.tmp[0] = eb; \ - memset(u.tmp + 1, 0, j - 2); \ - u.tmp[j - 1] = 0x80; \ - } \ - keccak_core(kc, u.tmp, j, lim); \ - /* Finalize the "lane complement" */ \ - kc->u.narrow[ 2] = ~kc->u.narrow[ 2]; \ - kc->u.narrow[ 3] = ~kc->u.narrow[ 3]; \ - kc->u.narrow[ 4] = ~kc->u.narrow[ 4]; \ - kc->u.narrow[ 5] = ~kc->u.narrow[ 5]; \ - kc->u.narrow[16] = ~kc->u.narrow[16]; \ - kc->u.narrow[17] = ~kc->u.narrow[17]; \ - kc->u.narrow[24] = ~kc->u.narrow[24]; \ - kc->u.narrow[25] = ~kc->u.narrow[25]; \ - kc->u.narrow[34] = ~kc->u.narrow[34]; \ - kc->u.narrow[35] = ~kc->u.narrow[35]; \ - kc->u.narrow[40] = ~kc->u.narrow[40]; \ - kc->u.narrow[41] = ~kc->u.narrow[41]; \ - /* un-interleave */ \ - for (j = 0; j < 50; j += 2) \ - UNINTERLEAVE(kc->u.narrow[j], kc->u.narrow[j + 1]); \ - for (j = 0; j < d; j += 4) \ - sph_enc32le_aligned(u.tmp + j, kc->u.narrow[j >> 2]); \ - memcpy(dst, u.tmp, d); \ - keccak_init(kc, (unsigned)d << 3); \ - } \ +#define DEFCLOSE(d, lim) \ + static void keccak_close##d(sph_keccak_context *kc, unsigned ub, unsigned n, \ + void *dst) { \ + unsigned eb; \ + union { \ + unsigned char tmp[lim + 1]; \ + sph_u64 dummy; /* for alignment */ \ + } u; \ + size_t j; \ + \ + eb = (0x100 | (ub & 0xFF)) >> (8 - n); \ + if (kc->ptr == (lim - 1)) { \ + if (n == 7) { \ + u.tmp[0] = eb; \ + memset(u.tmp + 1, 0, lim - 1); \ + u.tmp[lim] = 0x80; \ + j = 1 + lim; \ + } else { \ + u.tmp[0] = eb | 0x80; \ + j = 1; \ + } \ + } else { \ + j = lim - kc->ptr; \ + u.tmp[0] = eb; \ + memset(u.tmp + 1, 0, j - 2); \ + u.tmp[j - 1] = 0x80; \ + } \ + keccak_core(kc, u.tmp, j, lim); \ + /* Finalize the "lane complement" */ \ + kc->u.narrow[2] = ~kc->u.narrow[2]; \ + kc->u.narrow[3] = ~kc->u.narrow[3]; \ + kc->u.narrow[4] = ~kc->u.narrow[4]; \ + kc->u.narrow[5] = ~kc->u.narrow[5]; \ + kc->u.narrow[16] = ~kc->u.narrow[16]; \ + kc->u.narrow[17] = ~kc->u.narrow[17]; \ + kc->u.narrow[24] = ~kc->u.narrow[24]; \ + kc->u.narrow[25] = ~kc->u.narrow[25]; \ + kc->u.narrow[34] = ~kc->u.narrow[34]; \ + kc->u.narrow[35] = ~kc->u.narrow[35]; \ + kc->u.narrow[40] = ~kc->u.narrow[40]; \ + kc->u.narrow[41] = ~kc->u.narrow[41]; \ + /* un-interleave */ \ + for (j = 0; j < 50; j += 2) \ + UNINTERLEAVE(kc->u.narrow[j], kc->u.narrow[j + 1]); \ + for (j = 0; j < d; j += 4) \ + sph_enc32le_aligned(u.tmp + j, kc->u.narrow[j >> 2]); \ + memcpy(dst, u.tmp, d); \ + keccak_init(kc, (unsigned)d << 3); \ + } #endif @@ -1798,146 +1788,81 @@ DEFCLOSE(48, 104) DEFCLOSE(64, 72) /* see sph_keccak.h */ -void -sph_keccak224_init(void *cc) -{ - keccak_init(cc, 224); -} - -/* see sph_keccak.h */ -void -sph_keccak224(void *cc, const void *data, size_t len) -{ - keccak_core(cc, data, len, 144); -} - -/* see sph_keccak.h */ -void -sph_keccak224_close(void *cc, void *dst) -{ - sph_keccak224_addbits_and_close(cc, 0, 0, dst); -} +void sph_keccak224_init(void *cc) { keccak_init(cc, 224); } /* see sph_keccak.h */ -void -sph_keccak224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) -{ - keccak_close28(cc, ub, n, dst); +void sph_keccak224(void *cc, const void *data, size_t len) { + keccak_core(cc, data, len, 144); } /* see sph_keccak.h */ -void -sph_keccak256_init(void *cc) -{ - keccak_init(cc, 256); +void sph_keccak224_close(void *cc, void *dst) { + sph_keccak224_addbits_and_close(cc, 0, 0, dst); } /* see sph_keccak.h */ -void -sph_keccak256(void *cc, const void *data, size_t len) -{ - keccak_core(cc, data, len, 136); +void sph_keccak224_addbits_and_close(void *cc, unsigned ub, unsigned n, + void *dst) { + keccak_close28(cc, ub, n, dst); } /* see sph_keccak.h */ -void -sph_keccak256_close(void *cc, void *dst) -{ - sph_keccak256_addbits_and_close(cc, 0, 0, dst); -} +void sph_keccak256_init(void *cc) { keccak_init(cc, 256); } /* see sph_keccak.h */ -void -sph_keccak256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) -{ - keccak_close32(cc, ub, n, dst); +void sph_keccak256(void *cc, const void *data, size_t len) { + keccak_core(cc, data, len, 136); } /* see sph_keccak.h */ -void -sph_flex_keccak256_close(void *cc, void *dst) -{ - sph_flex_keccak256_addbits_and_close(cc, 0, 0, dst); +void sph_keccak256_close(void *cc, void *dst) { + sph_keccak256_addbits_and_close(cc, 0, 0, dst); } /* see sph_keccak.h */ -void -sph_flex_keccak256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) -{ - flex_keccak_close32(cc, ub, n, dst); +void sph_keccak256_addbits_and_close(void *cc, unsigned ub, unsigned n, + void *dst) { + keccak_close32(cc, ub, n, dst); } /* see sph_keccak.h */ -void -sph_keccak384_init(void *cc) -{ - keccak_init(cc, 384); -} +void sph_keccak384_init(void *cc) { keccak_init(cc, 384); } /* see sph_keccak.h */ -void -sph_keccak384(void *cc, const void *data, size_t len) -{ - keccak_core(cc, data, len, 104); +void sph_keccak384(void *cc, const void *data, size_t len) { + keccak_core(cc, data, len, 104); } /* see sph_keccak.h */ -void -sph_keccak384_close(void *cc, void *dst) -{ - sph_keccak384_addbits_and_close(cc, 0, 0, dst); +void sph_keccak384_close(void *cc, void *dst) { + sph_keccak384_addbits_and_close(cc, 0, 0, dst); } /* see sph_keccak.h */ -void -sph_keccak384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) -{ - keccak_close48(cc, ub, n, dst); +void sph_keccak384_addbits_and_close(void *cc, unsigned ub, unsigned n, + void *dst) { + keccak_close48(cc, ub, n, dst); } /* see sph_keccak.h */ -void -sph_keccak512_init(void *cc) -{ - keccak_init(cc, 512); -} +void sph_keccak512_init(void *cc) { keccak_init(cc, 512); } /* see sph_keccak.h */ -void -sph_keccak512(void *cc, const void *data, size_t len) -{ - keccak_core(cc, data, len, 72); +void sph_keccak512(void *cc, const void *data, size_t len) { + keccak_core(cc, data, len, 72); } /* see sph_keccak.h */ -void -sph_keccak512_close(void *cc, void *dst) -{ - sph_keccak512_addbits_and_close(cc, 0, 0, dst); +void sph_keccak512_close(void *cc, void *dst) { + sph_keccak512_addbits_and_close(cc, 0, 0, dst); } /* see sph_keccak.h */ -void -sph_keccak512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) -{ - keccak_close64(cc, ub, n, dst); +void sph_keccak512_addbits_and_close(void *cc, unsigned ub, unsigned n, + void *dst) { + keccak_close64(cc, ub, n, dst); } -/* see sph_keccak.h */ -void -sph_flex_keccak512_close(void *cc, void *dst) -{ - sph_flex_keccak512_addbits_and_close(cc, 0, 0, dst); -} - -/* see sph_keccak.h */ -void -sph_flex_keccak512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) -{ - flex_keccak_close64(cc, ub, n, dst); -} - - #ifdef __cplusplus } #endif diff --git a/src/Native/libcryptonight/xmrig/crypto/ghostrider/sph_keccak.h b/src/Native/libcryptonight/xmrig/crypto/ghostrider/sph_keccak.h index 3d755dd176..ebbdc0c7ae 100644 --- a/src/Native/libcryptonight/xmrig/crypto/ghostrider/sph_keccak.h +++ b/src/Native/libcryptonight/xmrig/crypto/ghostrider/sph_keccak.h @@ -7,7 +7,7 @@ * ==========================(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 @@ -15,10 +15,10 @@ * 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. @@ -37,31 +37,34 @@ #define SPH_KECCAK_H__ #ifdef __cplusplus -extern "C"{ +extern "C" { #endif -#include +// Taken from keccak-gate.h +extern int hard_coded_eb; + #include "sph_types.h" +#include /** * Output size (in bits) for Keccak-224. */ -#define SPH_SIZE_keccak224 224 +#define SPH_SIZE_keccak224 224 /** * Output size (in bits) for Keccak-256. */ -#define SPH_SIZE_keccak256 256 +#define SPH_SIZE_keccak256 256 /** * Output size (in bits) for Keccak-384. */ -#define SPH_SIZE_keccak384 384 +#define SPH_SIZE_keccak384 384 /** * Output size (in bits) for Keccak-512. */ -#define SPH_SIZE_keccak512 512 +#define SPH_SIZE_keccak512 512 /** * This structure is a context for Keccak computations: it contains the @@ -75,14 +78,14 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[144]; /* first field, for alignment */ - size_t ptr, lim; - union { + unsigned char buf[144]; /* first field, for alignment */ + size_t ptr, lim; + union { #if SPH_64 - sph_u64 wide[25]; + sph_u64 wide[25]; #endif - sph_u32 narrow[50]; - } u; + sph_u32 narrow[50]; + } u; #endif } sph_keccak_context; @@ -148,8 +151,8 @@ void sph_keccak224_close(void *cc, void *dst); * @param n the number of extra bits (0 to 7) * @param dst the destination buffer */ -void sph_keccak224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); +void sph_keccak224_addbits_and_close(void *cc, unsigned ub, unsigned n, + void *dst); /** * Initialize a Keccak-256 context. This process performs no memory allocation. @@ -193,35 +196,8 @@ void sph_keccak256_close(void *cc, void *dst); * @param n the number of extra bits (0 to 7) * @param dst the destination buffer */ -void sph_keccak256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); - -/** - * Terminate the current Keccak-256 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 Keccak-256 context - * @param dst the destination buffer - */ -void sph_flex_keccak256_close(void *cc, void *dst); - -/** - * Add a few additional bits (0 to 7) to the current computation, then - * terminate it and output the result in the provided buffer, which must - * be wide enough to accomodate the result (32 bytes). If bit number i - * in ub has value 2^i, then the extra bits are those - * numbered 7 downto 8-n (this is the big-endian convention at the byte - * level). The context is automatically reinitialized. - * - * @param cc the Keccak-256 context - * @param ub the extra bits - * @param n the number of extra bits (0 to 7) - * @param dst the destination buffer - */ -void sph_flex_keccak256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); +void sph_keccak256_addbits_and_close(void *cc, unsigned ub, unsigned n, + void *dst); /** * Initialize a Keccak-384 context. This process performs no memory allocation. @@ -265,8 +241,8 @@ void sph_keccak384_close(void *cc, void *dst); * @param n the number of extra bits (0 to 7) * @param dst the destination buffer */ -void sph_keccak384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); +void sph_keccak384_addbits_and_close(void *cc, unsigned ub, unsigned n, + void *dst); /** * Initialize a Keccak-512 context. This process performs no memory allocation. @@ -310,35 +286,8 @@ void sph_keccak512_close(void *cc, void *dst); * @param n the number of extra bits (0 to 7) * @param dst the destination buffer */ -void sph_keccak512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); - -/** - * Terminate the current Keccak-512 computation and output the result into - * the provided buffer. The destination buffer must be wide enough to - * accomodate the result (64 bytes). The context is automatically - * reinitialized. - * - * @param cc the Keccak-512 context - * @param dst the destination buffer - */ -void sph_flex_keccak512_close(void *cc, void *dst); - -/** - * Add a few additional bits (0 to 7) to the current computation, then - * terminate it and output the result in the provided buffer, which must - * be wide enough to accomodate the result (64 bytes). If bit number i - * in ub has value 2^i, then the extra bits are those - * numbered 7 downto 8-n (this is the big-endian convention at the byte - * level). The context is automatically reinitialized. - * - * @param cc the Keccak-512 context - * @param ub the extra bits - * @param n the number of extra bits (0 to 7) - * @param dst the destination buffer - */ -void sph_flex_keccak512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); +void sph_keccak512_addbits_and_close(void *cc, unsigned ub, unsigned n, + void *dst); #ifdef __cplusplus } diff --git a/src/Native/libcryptonote/Makefile b/src/Native/libcryptonote/Makefile index 97ee8ed4a2..fe1f5b8cd0 100644 --- a/src/Native/libcryptonote/Makefile +++ b/src/Native/libcryptonote/Makefile @@ -15,8 +15,8 @@ OBJECTS = exports.o \ crypto/hash.o \ crypto/keccak.o \ common/base58.o \ - salvium_oracle/pricing_record.o \ - zephyr_oracle/pricing_record.o + zephyr_oracle/pricing_record.o \ + salvium_oracle/pricing_record.o all: $(TARGET) diff --git a/src/Native/libcryptonote/Makefile.MSys2 b/src/Native/libcryptonote/Makefile.MSys2 index 58de473e90..a60a8e5d69 100644 --- a/src/Native/libcryptonote/Makefile.MSys2 +++ b/src/Native/libcryptonote/Makefile.MSys2 @@ -18,10 +18,10 @@ OBJECTS = exports.o \ crypto/crypto-ops.o \ crypto/crypto-ops-data.o \ crypto/hash.o \ - crypto/keccak.o \ + crypto/keccak.o \ common/base58.o \ - salvium_oracle/pricing_record.o \ zephyr_oracle/pricing_record.o \ + salvium_oracle/pricing_record.o \ mingw_stubs.o all: $(TARGET) diff --git a/src/Native/libcryptonote/contrib/epee/include/misc_os_dependent.h b/src/Native/libcryptonote/contrib/epee/include/misc_os_dependent.h index 5fffde8d5a..7ad63ad2a2 100644 --- a/src/Native/libcryptonote/contrib/epee/include/misc_os_dependent.h +++ b/src/Native/libcryptonote/contrib/epee/include/misc_os_dependent.h @@ -91,31 +91,6 @@ namespace misc_utils } - inline int call_sys_cmd(const std::string& cmd) - { - std::cout << "# " << cmd << std::endl; - - FILE * fp ; - //char tstCommand[] ="ls *"; - char path[1000] = {0}; -#if !defined(__GNUC__) - fp = _popen(cmd.c_str(), "r"); -#else - fp = popen(cmd.c_str(), "r"); -#endif - while ( fgets( path, 1000, fp ) != NULL ) - std::cout << path; - -#if !defined(__GNUC__) - _pclose(fp); -#else - pclose(fp); -#endif - return 0; - - } - - inline std::string get_thread_string_id() { #if defined(_WIN32) diff --git a/src/Native/libcryptonote/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/src/Native/libcryptonote/contrib/epee/include/serialization/keyvalue_serialization_overloads.h index 5757d609bd..fc8b90a2cf 100644 --- a/src/Native/libcryptonote/contrib/epee/include/serialization/keyvalue_serialization_overloads.h +++ b/src/Native/libcryptonote/contrib/epee/include/serialization/keyvalue_serialization_overloads.h @@ -26,7 +26,6 @@ #pragma once -#include #include #include #include diff --git a/src/Native/libcryptonote/cryptonote_config.h b/src/Native/libcryptonote/cryptonote_config.h index 5a88aa5c34..0ab9856cc4 100644 --- a/src/Native/libcryptonote/cryptonote_config.h +++ b/src/Native/libcryptonote/cryptonote_config.h @@ -1,13 +1,16 @@ #pragma once -#define CURRENT_TRANSACTION_VERSION 1 -#define POU_TRANSACTION_VERSION 6 -#define COLLATERAL_TRANSACTION_VERSION 7 -#define HAVEN_TYPES_TRANSACTION_VERSION 8 -#define OFFSHORE_TRANSACTION_VERSION 3 -#define HF_VERSION_XASSET_FEES_V2 17 -#define HF_VERSION_HAVEN2 18 -#define HF_VERSION_USE_COLLATERAL 20 +#define CURRENT_TRANSACTION_VERSION 1 +#define POU_TRANSACTION_VERSION 6 +#define COLLATERAL_TRANSACTION_VERSION 7 +#define OFFSHORE_TRANSACTION_VERSION 3 +#define HF_VERSION_XASSET_FEES_V2 17 +#define HF_VERSION_HAVEN2 18 +#define HF_VERSION_USE_COLLATERAL 20 + +// Salvium +#define HF_VERSION_ENABLE_N_OUTS 2 +#define TRANSACTION_VERSION_N_OUTS 3 // UNLOCK TIMES #define TX_V6_OFFSHORE_UNLOCK_BLOCKS 21*720 // 21 day unlock time diff --git a/src/Native/libcryptonote/cryptonote_core/cryptonote_basic.h b/src/Native/libcryptonote/cryptonote_core/cryptonote_basic.h index 1e8d66e3b1..dc72133363 100644 --- a/src/Native/libcryptonote/cryptonote_core/cryptonote_basic.h +++ b/src/Native/libcryptonote/cryptonote_core/cryptonote_basic.h @@ -61,7 +61,7 @@ namespace cryptonote RETURN = 7, MAX = 7 }; - + /* outputs */ struct txout_to_script @@ -102,48 +102,6 @@ namespace cryptonote END_SERIALIZE() }; - // outputs <= HF_VERSION_VIEW_TAGS - struct txout_haven_key - { - txout_haven_key() { } - txout_haven_key(const crypto::public_key &_key, const std::string &_asset_type, const uint64_t &_unlock_time, const bool &_is_collateral, const bool &_is_collateral_change) : key(_key), asset_type(_asset_type), unlock_time(_unlock_time), is_collateral(_is_collateral), is_collateral_change(_is_collateral_change) { } - crypto::public_key key; - std::string asset_type; - uint64_t unlock_time; - bool is_collateral; - bool is_collateral_change; - - BEGIN_SERIALIZE_OBJECT() - FIELD(key) - FIELD(asset_type) - VARINT_FIELD(unlock_time) - FIELD(is_collateral) - FIELD(is_collateral_change) - END_SERIALIZE() - }; - - // outputs >= HF_VERSION_VIEW_TAGS - struct txout_haven_tagged_key - { - txout_haven_tagged_key() { } - txout_haven_tagged_key(const crypto::public_key &_key, const std::string &_asset_type, const uint64_t &_unlock_time, const bool &_is_collateral, const bool &_is_collateral_change, const crypto::view_tag &_view_tag) : key(_key), asset_type(_asset_type), unlock_time(_unlock_time), is_collateral(_is_collateral), is_collateral_change(_is_collateral_change), view_tag(_view_tag) { } - crypto::public_key key; - std::string asset_type; - uint64_t unlock_time; - bool is_collateral; - bool is_collateral_change; - crypto::view_tag view_tag; // optimization to reduce scanning time - - BEGIN_SERIALIZE_OBJECT() - FIELD(key) - FIELD(asset_type) - VARINT_FIELD(unlock_time) - FIELD(is_collateral) - FIELD(is_collateral_change) - FIELD(view_tag) - END_SERIALIZE() - }; - struct txout_offshore { txout_offshore() { } @@ -164,22 +122,6 @@ namespace cryptonote END_SERIALIZE() }; - // ZEPHYR - struct txout_zephyr_tagged_key - { - txout_zephyr_tagged_key() { } - txout_zephyr_tagged_key(const crypto::public_key &_key, const std::string &_asset_type, const crypto::view_tag &_view_tag) : key(_key), asset_type(_asset_type), view_tag(_view_tag) { } - crypto::public_key key; - std::string asset_type; - crypto::view_tag view_tag; // optimization to reduce scanning time - - BEGIN_SERIALIZE_OBJECT() - FIELD(key) - FIELD(asset_type) - FIELD(view_tag) - END_SERIALIZE() - }; - // SALVIUM struct txout_salvium_key { @@ -215,6 +157,22 @@ namespace cryptonote END_SERIALIZE() }; + // ZEPHYR + struct txout_zephyr_tagged_key + { + txout_zephyr_tagged_key() { } + txout_zephyr_tagged_key(const crypto::public_key &_key, const std::string &_asset_type, const crypto::view_tag &_view_tag) : key(_key), asset_type(_asset_type), view_tag(_view_tag) { } + crypto::public_key key; + std::string asset_type; + crypto::view_tag view_tag; // optimization to reduce scanning time + + BEGIN_SERIALIZE_OBJECT() + FIELD(key) + FIELD(asset_type) + FIELD(view_tag) + END_SERIALIZE() + }; + /* inputs */ struct txin_gen @@ -293,21 +251,6 @@ namespace cryptonote END_SERIALIZE() }; - struct txin_haven_key - { - uint64_t amount; - std::string asset_type; - std::vector key_offsets; - crypto::key_image k_image; // double spending protection - - BEGIN_SERIALIZE_OBJECT() - VARINT_FIELD(amount) - FIELD(asset_type) - FIELD(key_offsets) - FIELD(k_image) - END_SERIALIZE() - }; - struct txin_xasset { uint64_t amount; @@ -323,7 +266,7 @@ namespace cryptonote END_SERIALIZE() }; - struct txin_zephyr_key + struct txin_salvium_key { uint64_t amount; std::string asset_type; @@ -337,8 +280,8 @@ namespace cryptonote FIELD(k_image) END_SERIALIZE() }; - - struct txin_salvium_key + + struct txin_zephyr_key { uint64_t amount; std::string asset_type; @@ -353,14 +296,13 @@ namespace cryptonote END_SERIALIZE() }; - typedef boost::variant txin_v; - typedef boost::variant txin_zephyr_v; + typedef boost::variant txin_v; typedef boost::variant txin_salvium_v; typedef boost::variant txout_target_v; - typedef boost::variant txout_xhv_target_v; - typedef boost::variant txout_salvium_target_v; + typedef boost::variant txout_xhv_target_v; + typedef boost::variant txout_salvium_target_v; typedef boost::variant txout_stablero_target_v; struct tx_out @@ -385,10 +327,10 @@ namespace cryptonote END_SERIALIZE() }; - struct tx_out_zephyr + struct tx_out_salvium { uint64_t amount; - txout_stablero_target_v target; + txout_salvium_target_v target; BEGIN_SERIALIZE_OBJECT() VARINT_FIELD(amount) @@ -396,10 +338,10 @@ namespace cryptonote END_SERIALIZE() }; - struct tx_out_salvium + struct tx_out_zephyr { uint64_t amount; - txout_salvium_target_v target; + txout_stablero_target_v target; BEGIN_SERIALIZE_OBJECT() VARINT_FIELD(amount) @@ -427,12 +369,11 @@ namespace cryptonote uint64_t unlock_time; //number of block (or time), used as a limitation like: spend this tx not early then block/time std::vector vin; - std::vector vin_zephyr; std::vector vin_salvium; std::vector vout; + std::vector vout_salvium; std::vector vout_xhv; std::vector vout_zephyr; - std::vector vout_salvium; //extra std::vector extra; // Block height to use PR from @@ -443,12 +384,15 @@ namespace cryptonote uint64_t amount_minted; std::vector output_unlock_times; std::vector collateral_indices; - // SALVIUM-SPECIFIC FIELDS // TX type cryptonote::salvium_transaction_type tx_type; // Return address crypto::public_key return_address; + // Return address list (must be at least 1 and at most BULLETPROOF_MAX_OUTPUTS-1 - the "-1" is for the change output) + std::vector return_address_list; + //return_address_change_mask + std::vector return_address_change_mask; // Return TX public key crypto::public_key return_pubkey; // Source asset type @@ -460,7 +404,6 @@ namespace cryptonote // Slippage limit uint64_t amount_slippage_limit; - // // NOTE: Loki specific // @@ -479,308 +422,82 @@ namespace cryptonote }; BEGIN_SERIALIZE() - if (blob_type == BLOB_TYPE_CRYPTONOTE_XHV) { - VARINT_FIELD(version) - //if(version == 0 || CURRENT_TRANSACTION_VERSION < version) return false; - - // Only transactions prior to HAVEN_TYPES_TRANSACTION_VERSION are permitted to be anything other than HAVEN_TYPES and need translation - if (version < HAVEN_TYPES_TRANSACTION_VERSION) { - - if (version < POU_TRANSACTION_VERSION) { - VARINT_FIELD(unlock_time) - } - if (!typename Archive::is_saving()) { - FIELD(vin) - FIELD(vout_xhv) - FIELD(extra) - if(version >= OFFSHORE_TRANSACTION_VERSION) { - VARINT_FIELD(pricing_record_height) - if (version < 5) - FIELD(offshore_data) - if (version >= POU_TRANSACTION_VERSION) { - FIELD(output_unlock_times) - if (vout_xhv.size() != output_unlock_times.size()) { - return false; - } - } - VARINT_FIELD(amount_burnt) - VARINT_FIELD(amount_minted) - if (version >= COLLATERAL_TRANSACTION_VERSION && amount_burnt) { - FIELD(collateral_indices) - if (collateral_indices.size() != 2) { - return false; - } - for (const auto vout_idx: collateral_indices) { - if (vout_idx >= vout_xhv.size()) - return false; - } - } - } - std::vector vin_tmp(vin); - bool is_conversion_tx = (amount_burnt != 0); - bool is_offshore_tx = is_conversion_tx; - bool is_onshore_tx = false; - vin.clear(); - for (auto &vin_entry: vin_tmp) { - if (vin_entry.type() == typeid(txin_gen)) { - vin.push_back(vin_entry); - continue; - } - txin_haven_key in; - if (vin_entry.type() == typeid(txin_to_key)) { - in.asset_type = "XHV"; - in.amount = boost::get(vin_entry).amount; - in.key_offsets = boost::get(vin_entry).key_offsets; - in.k_image = boost::get(vin_entry).k_image; - } else if (vin_entry.type() == typeid(txin_offshore)) { - is_offshore_tx = false; - is_onshore_tx = false; - in.asset_type = "XUSD"; - in.amount = boost::get(vin_entry).amount; - in.key_offsets = boost::get(vin_entry).key_offsets; - in.k_image = boost::get(vin_entry).k_image; - } else if (vin_entry.type() == typeid(txin_onshore)) { - is_offshore_tx = false; - is_onshore_tx = true; - in.asset_type = "XUSD"; - in.amount = boost::get(vin_entry).amount; - in.key_offsets = boost::get(vin_entry).key_offsets; - in.k_image = boost::get(vin_entry).k_image; - } else if (vin_entry.type() == typeid(txin_xasset)) { - is_offshore_tx = false; - is_onshore_tx = false; - in.amount = boost::get(vin_entry).amount; - in.key_offsets = boost::get(vin_entry).key_offsets; - in.k_image = boost::get(vin_entry).k_image; - in.asset_type = boost::get(vin_entry).asset_type; - } else { - return false; - } - vin.push_back(in); - } - std::vector vout_tmp(vout_xhv); - vout_xhv.clear(); - for (size_t i=0; i(vout_tmp[i].target).key; - } else if (vout_tmp[i].target.type() == typeid(txout_offshore)) { - out.asset_type = "XUSD"; - out.key = boost::get(vout_tmp[i].target).key; - } else if (vout_tmp[i].target.type() == typeid(txout_xasset)) { - out.asset_type = boost::get(vout_tmp[i].target).asset_type; - out.key = boost::get(vout_tmp[i].target).key; - } else { - return false; - } - out.unlock_time = (version >= POU_TRANSACTION_VERSION) ? output_unlock_times[i] : unlock_time; - out.is_collateral = false; - out.is_collateral_change = false; - if (version >= COLLATERAL_TRANSACTION_VERSION && amount_burnt) { - if (((is_onshore_tx) && - (collateral_indices[0] == i)) || - ((!is_onshore_tx) && - (is_offshore_tx) && - (collateral_indices[0] == i && collateral_indices[1] == 0))) { - out.is_collateral = true; - } - if (is_onshore_tx && collateral_indices[1] == i) { - out.is_collateral_change = true; - } - } - tx_out_xhv foo; - foo.amount = vout_tmp[i].amount; - foo.target = out; - vout_xhv.push_back(foo); - } - return true; - } - bool is_offshore_tx = (amount_burnt != 0); - bool is_onshore_tx = false; - std::vector vin_tmp; - vin_tmp.reserve(vin.size()); - for (auto &vin_entry_v: vin) { - if (vin_entry_v.type() == typeid(txin_gen)) { - vin_tmp.push_back(vin_entry_v); - continue; - } - txin_haven_key vin_entry = boost::get(vin_entry_v); - if (vin_entry.asset_type == "XHV") { - txin_to_key in; - in.amount = vin_entry.amount; - in.key_offsets = vin_entry.key_offsets; - in.k_image = vin_entry.k_image; - vin_tmp.push_back(in); - } else if (vin_entry.asset_type == "XUSD") { - is_offshore_tx = false; - int xhv_outputs = std::count_if(vout_xhv.begin(), vout_xhv.end(), [](tx_out_xhv &foo_v) { - if (foo_v.target.type() == typeid(txout_haven_key)) { - txout_haven_key out = boost::get(foo_v.target); - return out.asset_type == "XHV"; - } else if (foo_v.target.type() == typeid(txout_haven_tagged_key)) { - txout_haven_tagged_key out = boost::get(foo_v.target); - return out.asset_type == "XHV"; - } else { - return false; - } - }); - if (xhv_outputs) { - is_onshore_tx = true; - txin_onshore in; - in.amount = vin_entry.amount; - in.key_offsets = vin_entry.key_offsets; - in.k_image = vin_entry.k_image; - vin_tmp.push_back(in); - } else { - txin_offshore in; - in.amount = vin_entry.amount; - in.key_offsets = vin_entry.key_offsets; - in.k_image = vin_entry.k_image; - vin_tmp.push_back(in); - } - } else { - is_offshore_tx = false; - txin_xasset in; - in.amount = vin_entry.amount; - in.asset_type = vin_entry.asset_type; - in.key_offsets = vin_entry.key_offsets; - in.k_image = vin_entry.k_image; - vin_tmp.push_back(in); - } - } - std::vector vout_tmp; - vout_tmp.reserve(vout_xhv.size()); - output_unlock_times.resize(vout_xhv.size()); - std::vector collateral_indices_temp; - collateral_indices_temp.resize(2); - for (size_t i=0; i(vout_xhv[i].target); - tx_out_xhv foo; - foo.amount = vout_xhv[i].amount; - if (outhk.asset_type == "XHV") { - txout_to_key out; - out.key = outhk.key; - foo.target = out; - } else if (outhk.asset_type == "XUSD") { - txout_offshore out; - out.key = outhk.key; - foo.target = out; - } else { - txout_xasset out; - out.asset_type = outhk.asset_type; - out.key = outhk.key; - foo.target = out; - } - output_unlock_times[i] = outhk.unlock_time; - if (outhk.is_collateral) { - collateral_indices_temp[0] = i; - } else if (outhk.is_collateral_change) { - collateral_indices_temp[1] = i; - } - vout_tmp.push_back(foo); - } - FIELD_N("vin", vin_tmp) - FIELD_N("vout", vout_tmp) - FIELD(extra) - if(version >= OFFSHORE_TRANSACTION_VERSION) { - VARINT_FIELD(pricing_record_height) - if (version < 5) - FIELD(offshore_data) - if (version >= POU_TRANSACTION_VERSION) { - FIELD(output_unlock_times) - if (vout_xhv.size() != output_unlock_times.size()) { - return false; - } - } - VARINT_FIELD(amount_burnt) - VARINT_FIELD(amount_minted) - if (version >= COLLATERAL_TRANSACTION_VERSION && amount_burnt) { - if (collateral_indices.size() != 2) { - if ((is_offshore_tx || is_onshore_tx) && collateral_indices_temp.size() != 2) { - return false; - } - if (is_offshore_tx || is_onshore_tx) { - collateral_indices = collateral_indices_temp; - } else { - collateral_indices.clear(); - collateral_indices.push_back(0); - collateral_indices.push_back(0); - } - } - FIELD(collateral_indices) - for (const auto vout_idx: collateral_indices) { - if (vout_idx >= vout_xhv.size()) - return false; - } - } - } - return true; - } - - FIELD(vin) - FIELD(vout_xhv) - FIELD(extra) - VARINT_FIELD(pricing_record_height) - VARINT_FIELD(amount_burnt) - VARINT_FIELD(amount_minted) - - } else if (blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) { - - VARINT_FIELD(version) - //if(version == 0 || CURRENT_TRANSACTION_VERSION < version) return false; + VARINT_FIELD(version) + if (version > loki_version_2 && (blob_type == BLOB_TYPE_CRYPTONOTE_LOKI || blob_type == BLOB_TYPE_CRYPTONOTE_XTNC)) + { + FIELD(output_unlock_times) + if (version == loki_version_3_per_output_unlock_times) + FIELD(is_deregister) + } + if (blob_type != BLOB_TYPE_CRYPTONOTE_XHV || version < POU_TRANSACTION_VERSION) VARINT_FIELD(unlock_time) + + if (blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) FIELD(vin_salvium) + else + FIELD(vin) + + if (blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) FIELD(vout_salvium) - FIELD(extra) + else if (blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR) + FIELD(vout_zephyr) + else if (blob_type == BLOB_TYPE_CRYPTONOTE_XHV) + FIELD(vout_xhv) + else + FIELD(vout) + + if (blob_type == BLOB_TYPE_CRYPTONOTE_LOKI || blob_type == BLOB_TYPE_CRYPTONOTE_XTNC) + { + if (version >= loki_version_3_per_output_unlock_times && vout.size() != output_unlock_times.size()) return false; + } + FIELD(extra) + if ((blob_type == BLOB_TYPE_CRYPTONOTE_LOKI || blob_type == BLOB_TYPE_CRYPTONOTE_XTNC) && version >= loki_version_4_tx_types) + { + VARINT_FIELD(type) + if (static_cast(type) >= loki_type_count) return false; + } + if (blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) { VARINT_FIELD(tx_type) if (tx_type != cryptonote::salvium_transaction_type::PROTOCOL) { VARINT_FIELD(amount_burnt) if (tx_type != cryptonote::salvium_transaction_type::MINER) { - FIELD(return_address) - FIELD(return_pubkey) + if (tx_type == cryptonote::salvium_transaction_type::TRANSFER && version >= TRANSACTION_VERSION_N_OUTS) { + FIELD(return_address_list) + FIELD(return_address_change_mask) + } else { + FIELD(return_address) + FIELD(return_pubkey) + } FIELD(source_asset_type) FIELD(destination_asset_type) VARINT_FIELD(amount_slippage_limit) } } - - } else { - - VARINT_FIELD(version) - if (version > loki_version_2 && (blob_type == BLOB_TYPE_CRYPTONOTE_LOKI || blob_type == BLOB_TYPE_CRYPTONOTE_XTNC)) + } else if (blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR) { + VARINT_FIELD(pricing_record_height) + VARINT_FIELD(amount_burnt) + VARINT_FIELD(amount_minted) + } + if (blob_type == BLOB_TYPE_CRYPTONOTE_XHV && version >= OFFSHORE_TRANSACTION_VERSION) { + VARINT_FIELD(pricing_record_height) + if (version < 5) + FIELD(offshore_data) + if (version >= POU_TRANSACTION_VERSION) { FIELD(output_unlock_times) - if (version == loki_version_3_per_output_unlock_times) - FIELD(is_deregister) } - - VARINT_FIELD(unlock_time) - - if (blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR) - FIELD(vin_zephyr) - else - FIELD(vin) - - if (blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR) - FIELD(vout_zephyr) - else - FIELD(vout) - - if (blob_type == BLOB_TYPE_CRYPTONOTE_LOKI || blob_type == BLOB_TYPE_CRYPTONOTE_XTNC) - { - if (version >= loki_version_3_per_output_unlock_times && vout.size() != output_unlock_times.size()) return false; - } - FIELD(extra) - if ((blob_type == BLOB_TYPE_CRYPTONOTE_LOKI || blob_type == BLOB_TYPE_CRYPTONOTE_XTNC) && version >= loki_version_4_tx_types) - { - VARINT_FIELD(type) - if (static_cast(type) >= loki_type_count) return false; - } - if (blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR) { - VARINT_FIELD(pricing_record_height) - VARINT_FIELD(amount_burnt) - VARINT_FIELD(amount_minted) + if (version >= POU_TRANSACTION_VERSION && vout_xhv.size() != output_unlock_times.size()) return false; + VARINT_FIELD(amount_burnt) + VARINT_FIELD(amount_minted) + if (version >= COLLATERAL_TRANSACTION_VERSION && amount_burnt) { + FIELD(collateral_indices) + if (collateral_indices.size() != 2) { + return false; + } + for (const auto vout_idx: collateral_indices) { + if (vout_idx >= vout.size()) + return false; + } } } END_SERIALIZE() @@ -837,39 +554,28 @@ namespace cryptonote else { ar.tag("rct_signatures"); - if (blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM ? !vin_salvium.empty() : (blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR ? !vin_zephyr.empty() : !vin.empty())) + if (blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM ? !vin_salvium.empty() : !vin.empty()) { ar.begin_object(); - bool r; - if (blob_type == BLOB_TYPE_CRYPTONOTE_XHV) - r = rct_signatures.serialize_rctsig_base(ar, vin.size(), vout_xhv.size()); - else if (blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR) - r = rct_signatures.serialize_rctsig_base(ar, vin_zephyr.size(), vout_zephyr.size()); - else if (blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) - r = rct_signatures.serialize_rctsig_base(ar, vin_salvium.size(), vout_salvium.size()); - else - r = rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size()); + bool r = rct_signatures.serialize_rctsig_base(ar, blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM ? vin_salvium.size() : vin.size(), blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR ? vout_zephyr.size() : blob_type != BLOB_TYPE_CRYPTONOTE_XHV ? vout.size() : vout_xhv.size()); if (!r || !ar.stream().good()) return false; ar.end_object(); if (rct_signatures.type != rct::RCTTypeNull) { ar.tag("rctsig_prunable"); ar.begin_object(); - if (blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR) { - r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin_zephyr.size(), vout_zephyr.size(), - vin_zephyr[0].type() == typeid(txin_zephyr_key) ? boost::get(vin_zephyr[0]).key_offsets.size() - 1 : 0); - } else if (blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) { + if (blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) { r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin_salvium.size(), vout_salvium.size(), vin_salvium[0].type() == typeid(txin_salvium_key) ? boost::get(vin_salvium[0]).key_offsets.size() - 1 : 0); + } else if (blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR) { + r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout_zephyr.size(), + vin[0].type() == typeid(txin_zephyr_key) ? boost::get(vin[0]).key_offsets.size() - 1 : 0); } else if (blob_type == BLOB_TYPE_CRYPTONOTE_XHV) { r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout_xhv.size(), vin.size() > 0 && vin[0].type() == typeid(txin_to_key) ? boost::get(vin[0]).key_offsets.size() - 1 : vin.size() > 0 && vin[0].type() == typeid(txin_offshore) ? boost::get(vin[0]).key_offsets.size() - 1 : vin.size() > 0 && vin[0].type() == typeid(txin_onshore) ? boost::get(vin[0]).key_offsets.size() - 1 : - vin.size() > 0 && vin[0].type() == typeid(txin_xasset) ? boost::get(vin[0]).key_offsets.size() - 1 : - vin.size() > 0 && vin[0].type() == typeid(txin_haven_key) ? boost::get(vin[0]).key_offsets.size() - 1 : - 0 - ); + vin.size() > 0 && vin[0].type() == typeid(txin_xasset) ? boost::get(vin[0]).key_offsets.size() - 1 : 0); } else { r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(), vin[0].type() == typeid(txin_to_key) ? boost::get(vin[0]).key_offsets.size() - 1 : 0); @@ -903,8 +609,9 @@ namespace cryptonote version = 0; unlock_time = 0; vin.clear(); - vin_zephyr.clear(); + vin_salvium.clear(); vout.clear(); + vout_salvium.clear(); vout_xhv.clear(); vout_zephyr.clear(); extra.clear(); @@ -915,6 +622,15 @@ namespace cryptonote amount_minted = 0; output_unlock_times.clear(); collateral_indices.clear(); + // Salvium-specific fields + type = cryptonote::salvium_transaction_type::UNSET; + return_address = null_pkey; + return_address_list.clear(); + return_address_change_mask.clear(); + return_pubkey = null_pkey; + source_asset_type.clear(); + destination_asset_type.clear(); + amount_slippage_limit = 0; } inline @@ -929,7 +645,7 @@ namespace cryptonote size_t operator()(const txin_offshore& txin) const {return txin.key_offsets.size();} size_t operator()(const txin_onshore& txin) const {return txin.key_offsets.size();} size_t operator()(const txin_xasset& txin) const {return txin.key_offsets.size();} - size_t operator()(const txin_haven_key& txin) const {return txin.key_offsets.size();} + size_t operator()(const txin_salvium_key& txin) const {return txin.key_offsets.size();} size_t operator()(const txin_zephyr_key& txin) const {return txin.key_offsets.size();} }; @@ -1077,9 +793,9 @@ namespace cryptonote if (blob_type == BLOB_TYPE_CRYPTONOTE_XTNC || blob_type == BLOB_TYPE_CRYPTONOTE_CUCKOO) FIELD(cycle) if (blob_type == BLOB_TYPE_CRYPTONOTE_TUBE) FIELD(cycle40) if (blob_type == BLOB_TYPE_CRYPTONOTE_XTA) FIELD(cycle48) - if (blob_type == BLOB_TYPE_CRYPTONOTE_XHV) { - FIELD(pricing_record) - } else if (blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) { + if (blob_type == BLOB_TYPE_CRYPTONOTE_XHV) FIELD(pricing_record) + + if (blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) { if (major_version >= 2) FIELD(salvium_pricing_record) } else if (blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR) { if (major_version >= 4) @@ -1190,6 +906,12 @@ namespace cryptonote KV_SERIALIZE(payment_id) END_KV_SERIALIZE_MAP() }; + + struct keypair + { + crypto::public_key pub; + crypto::secret_key sec; + }; //--------------------------------------------------------------- } @@ -1202,22 +924,19 @@ VARIANT_TAG(binary_archive, cryptonote::txin_gen, 0xff); VARIANT_TAG(binary_archive, cryptonote::txin_to_script, 0x0); VARIANT_TAG(binary_archive, cryptonote::txin_to_scripthash, 0x1); VARIANT_TAG(binary_archive, cryptonote::txin_to_key, 0x2); +VARIANT_TAG(binary_archive, cryptonote::txin_salvium_key, 0x2); VARIANT_TAG(binary_archive, cryptonote::txin_zephyr_key, 0x2); VARIANT_TAG(binary_archive, cryptonote::txin_offshore, 0x3); -VARIANT_TAG(binary_archive, cryptonote::txin_salvium_key, 0x2); VARIANT_TAG(binary_archive, cryptonote::txin_onshore, 0x4); VARIANT_TAG(binary_archive, cryptonote::txin_xasset, 0x5); -VARIANT_TAG(binary_archive, cryptonote::txin_haven_key, 0x6); VARIANT_TAG(binary_archive, cryptonote::txout_to_script, 0x0); VARIANT_TAG(binary_archive, cryptonote::txout_to_scripthash, 0x1); VARIANT_TAG(binary_archive, cryptonote::txout_to_key, 0x2); VARIANT_TAG(binary_archive, cryptonote::txout_salvium_key, 0x2); +VARIANT_TAG(binary_archive, cryptonote::txout_salvium_tagged_key, 0x3); VARIANT_TAG(binary_archive, cryptonote::txout_zephyr_tagged_key, 0x2); VARIANT_TAG(binary_archive, cryptonote::txout_to_tagged_key, 0x3); -VARIANT_TAG(binary_archive, cryptonote::txout_salvium_tagged_key, 0x3); VARIANT_TAG(binary_archive, cryptonote::txout_offshore, 0x3); VARIANT_TAG(binary_archive, cryptonote::txout_xasset, 0x5); -VARIANT_TAG(binary_archive, cryptonote::txout_haven_key, 0x6); -VARIANT_TAG(binary_archive, cryptonote::txout_haven_tagged_key, 0x7); VARIANT_TAG(binary_archive, cryptonote::transaction, 0xcc); VARIANT_TAG(binary_archive, cryptonote::block, 0xbb); diff --git a/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.cpp b/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.cpp index c4039093c9..b27c0d682d 100644 --- a/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.cpp @@ -163,6 +163,71 @@ namespace cryptonote return true; } //--------------------------------------------------------------- + bool get_inputs_money_amount(const transaction& tx, uint64_t& money) + { + money = 0; + if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) { + BOOST_FOREACH(const auto& in, tx.vin_salvium) + { + CHECKED_GET_SPECIFIC_VARIANT(in, const txin_salvium_key, tokey_in, false); + money += tokey_in.amount; + } + } else { + BOOST_FOREACH(const auto& in, tx.vin) + { + CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false); + money += tokey_in.amount; + } + } + return true; + } + //--------------------------------------------------------------- + uint64_t get_block_height(const block& b) + { + if (b.miner_tx.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) { + CHECK_AND_ASSERT_MES(b.miner_tx.vin_salvium.size() == 1, 0, "wrong miner tx in block: " << get_block_hash(b) << ", b.miner_tx.vin_salvium.size() != 1"); + CHECKED_GET_SPECIFIC_VARIANT(b.miner_tx.vin_salvium[0], const txin_gen, coinbase_in, 0); + return coinbase_in.height; + } else { + CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 1, 0, "wrong miner tx in block: " << get_block_hash(b) << ", b.miner_tx.vin.size() != 1"); + CHECKED_GET_SPECIFIC_VARIANT(b.miner_tx.vin[0], const txin_gen, coinbase_in, 0); + return coinbase_in.height; + } + } + //--------------------------------------------------------------- + bool check_inputs_types_supported(const transaction& tx) + { + if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) { + BOOST_FOREACH(const auto& in, tx.vin_salvium) + { + CHECK_AND_ASSERT_MES(in.type() == typeid(txin_salvium_key), false, "wrong variant type: " + << in.type().name() << ", expected " << typeid(txin_salvium_key).name() + << ", in transaction id=" << get_transaction_hash(tx)); + } + } else { + BOOST_FOREACH(const auto& in, tx.vin) + { + if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR) { + CHECK_AND_ASSERT_MES(in.type() == typeid(txin_zephyr_key), false, "wrong variant type: " + << in.type().name() << ", expected " << typeid(txin_zephyr_key).name() + << ", in transaction id=" << get_transaction_hash(tx)); + } else if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_XHV) { + CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key) || in.type() == typeid(txin_offshore) || in.type() == typeid(txin_onshore) || in.type() == typeid(txin_xasset), false, "wrong variant type: " + << in.type().name() << ", expected " << typeid(txin_to_key).name() + << "or " << typeid(txin_offshore).name() + << "or " << typeid(txin_onshore).name() + << "or " << typeid(txin_xasset).name() + << ", in transaction id=" << get_transaction_hash(tx)); + } else { + CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), false, "wrong variant type: " + << in.type().name() << ", expected " << typeid(txin_to_key).name() + << ", in transaction id=" << get_transaction_hash(tx)); + } + } + } + return true; + } + //--------------------------------------------------------------- std::string short_hash_str(const crypto::hash& h) { std::string res = string_tools::pod_to_hex(h); @@ -220,7 +285,7 @@ namespace cryptonote { std::stringstream ss; binary_archive ba(ss); - const size_t inputs = t.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM ? t.vin_salvium.size() : (t.blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR ? t.vin_zephyr.size() : t.vin.size()); + const size_t inputs = t.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM ? t.vin_salvium.size() : t.vin.size(); const size_t outputs = t.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM ? t.vout_salvium.size() : (t.blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR ? t.vout_zephyr.size() : (t.blob_type != BLOB_TYPE_CRYPTONOTE_XHV ? t.vout.size() : t.vout_xhv.size())); bool r = tt.rct_signatures.serialize_rctsig_base(ba, inputs, outputs); CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures base"); @@ -236,20 +301,19 @@ namespace cryptonote { std::stringstream ss; binary_archive ba(ss); - const size_t inputs = t.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM ? t.vin_salvium.size() : (t.blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR ? t.vin_zephyr.size() : t.vin.size()); + const size_t inputs = t.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM ? t.vin_salvium.size() : t.vin.size(); const size_t outputs = t.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM ? t.vout_salvium.size() : (t.blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR ? t.vout_zephyr.size() : (t.blob_type != BLOB_TYPE_CRYPTONOTE_XHV ? t.vout.size() : t.vout_xhv.size())); size_t mixin; if (t.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) { mixin = t.vin_salvium.empty() ? 0 : t.vin_salvium[0].type() == typeid(txin_salvium_key) ? boost::get(t.vin_salvium[0]).key_offsets.size() - 1 : 0; } else if (t.blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR) { - mixin = t.vin_zephyr.empty() ? 0 : t.vin_zephyr[0].type() == typeid(txin_zephyr_key) ? boost::get(t.vin_zephyr[0]).key_offsets.size() - 1 : 0; + mixin = t.vin.empty() ? 0 : t.vin[0].type() == typeid(txin_zephyr_key) ? boost::get(t.vin[0]).key_offsets.size() - 1 : 0; } else if (t.blob_type == BLOB_TYPE_CRYPTONOTE_XHV) { mixin = t.vin.empty() ? 0 : t.vin[0].type() == typeid(txin_to_key) ? boost::get(t.vin[0]).key_offsets.size() - 1 : t.vin[0].type() == typeid(txin_offshore) ? boost::get(t.vin[0]).key_offsets.size() - 1 : t.vin[0].type() == typeid(txin_onshore) ? boost::get(t.vin[0]).key_offsets.size() - 1 : t.vin[0].type() == typeid(txin_xasset) ? boost::get(t.vin[0]).key_offsets.size() - 1 : - t.vin[0].type() == typeid(txin_haven_key) ? boost::get(t.vin[0]).key_offsets.size() - 1 : 0; } else { mixin = t.vin.empty() ? 0 : t.vin[0].type() == typeid(txin_to_key) ? boost::get(t.vin[0]).key_offsets.size() - 1 : 0; @@ -287,7 +351,11 @@ namespace cryptonote } crypto::hash tree_root_hash = get_tx_tree_hash(b); blob.append(reinterpret_cast(&tree_root_hash), sizeof(tree_root_hash)); - blob.append(tools::get_varint_data(b.tx_hashes.size()+1)); + if (b.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) { + blob.append(tools::get_varint_data(b.tx_hashes.size() + (b.major_version >= HF_VERSION_ENABLE_N_OUTS ? 2 : 1))); + } else { + blob.append(tools::get_varint_data(b.tx_hashes.size()+1)); + } if (b.blob_type == BLOB_TYPE_CRYPTONOTE3) { blob.append(reinterpret_cast(&b.uncle), sizeof(b.uncle)); } @@ -373,7 +441,7 @@ namespace cryptonote ss << b_blob; binary_archive ba(ss); bool r = ::serialization::serialize(ba, b); - CHECK_AND_ASSERT_MES(r, false, "Failed to parse block from blob 1"); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse block from blob"); return true; } //--------------------------------------------------------------- diff --git a/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.h b/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.h index 098025b973..fa8654066e 100644 --- a/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.h +++ b/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.h @@ -78,9 +78,12 @@ namespace cryptonote bool get_block_header_hash(const block& b, crypto::hash& res); bool get_bytecoin_block_longhash(const block& blk, crypto::hash& res); bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b); + bool get_inputs_money_amount(const transaction& tx, uint64_t& money); std::map get_outs_money_amount(const transaction& tx); + bool check_inputs_types_supported(const transaction& tx); bool check_outs_valid(const transaction& tx); + uint64_t get_block_height(const block& b); std::vector relative_output_offsets_to_absolute(const std::vector& off); std::vector absolute_output_offsets_to_relative(const std::vector& off); //--------------------------------------------------------------- diff --git a/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.o b/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.o new file mode 100644 index 0000000000..2d08c0ec1f Binary files /dev/null and b/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.o differ diff --git a/src/Native/libcryptonote/exports.o b/src/Native/libcryptonote/exports.o new file mode 100644 index 0000000000..c7c8800b3a Binary files /dev/null and b/src/Native/libcryptonote/exports.o differ diff --git a/src/Native/libcryptonote/serialization/binary_archive.h b/src/Native/libcryptonote/serialization/binary_archive.h index 1671ed5d54..f28e45c0c1 100644 --- a/src/Native/libcryptonote/serialization/binary_archive.h +++ b/src/Native/libcryptonote/serialization/binary_archive.h @@ -48,7 +48,7 @@ template <> struct binary_archive : public binary_archive_base { explicit binary_archive(stream_type &s) : base_type(s) { - auto pos = stream_.tellg(); + stream_type::streampos pos = stream_.tellg(); stream_.seekg(0, std::ios_base::end); eof_pos_ = stream_.tellg(); stream_.seekg(pos); diff --git a/src/Native/libdero/Makefile b/src/Native/libdero/Makefile new file mode 100644 index 0000000000..942142bf0b --- /dev/null +++ b/src/Native/libdero/Makefile @@ -0,0 +1,49 @@ +CFLAGS += -g -Wall -c -O3 -fPIC -DNDEBUG -Wno-deprecated-declarations -Wno-maybe-uninitialized -flax-vector-conversions -Wno-unused-variable -Wunused-but-set-variable -Wno-unused-function $(CPU_FLAGS) $(HAVE_FEATURE) +CXXFLAGS += -g -Wall -O3 -fPIC -fpermissive -Wuninitialized -DNDEBUG -Wno-deprecated-declarations -Wno-maybe-uninitialized -flax-vector-conversions -Wno-unused-variable -Wunused-but-set-variable -Wno-unused-function -Wno-sign-compare -std=c++17 $(CPU_FLAGS) $(HAVE_FEATURE) + +ifneq ($($(UNAME_P),aarch64),$($(UNAME_P),arm64)) + CFLAGS += -mfloat-abi=hard -march=armv7-a -mfpu=neon + CXXFLAGS += -mfloat-abi=hard -march=armv7-a -mfpu=neon +else + CXXFLAGS += -march=native -m64 +endif + +LDFLAGS += -shared +LDLIBS = -lboost_atomic -lboost_context -lboost_chrono -lboost_program_options -lboost_thread -lpthread -lssl -lcrypto +TARGET = libdero.so + +OBJECTS = include/highwayhash/arch_specific.o include/highwayhash/c_bindings.o include/highwayhash/hh_portable.o include/highwayhash/scalar_sip_tree_hash.o include/highwayhash/sip_hash.o \ + include/libkeccak/digest.o include/libkeccak/libkeccak_behex_lower.o include/libkeccak/libkeccak_behex_upper.o include/libkeccak/libkeccak_cshake_initialise.o include/libkeccak/libkeccak_cshake_suffix.o \ + include/libkeccak/libkeccak_degeneralise_spec.o include/libkeccak/libkeccak_generalised_sum_fd.o include/libkeccak/libkeccak_hmac_copy.o include/libkeccak/libkeccak_hmac_create.o include/libkeccak/libkeccak_hmac_destroy.o \ + include/libkeccak/libkeccak_hmac_digest.o include/libkeccak/libkeccak_hmac_duplicate.o include/libkeccak/libkeccak_hmac_fast_destroy.o include/libkeccak/libkeccak_hmac_fast_digest.o include/libkeccak/libkeccak_hmac_fast_free.o \ + include/libkeccak/libkeccak_hmac_fast_update.o include/libkeccak/libkeccak_hmac_free.o include/libkeccak/libkeccak_hmac_initialise.o include/libkeccak/libkeccak_hmac_marshal.o include/libkeccak/libkeccak_hmac_reset.o \ + include/libkeccak/libkeccak_hmac_set_key.o include/libkeccak/libkeccak_hmac_unmarshal.o include/libkeccak/libkeccak_hmac_update.o include/libkeccak/libkeccak_hmac_wipe.o include/libkeccak/libkeccak_keccaksum_fd.o \ + include/libkeccak/libkeccak_rawshakesum_fd.o include/libkeccak/libkeccak_sha3sum_fd.o include/libkeccak/libkeccak_shakesum_fd.o include/libkeccak/libkeccak_spec_check.o include/libkeccak/libkeccak_spec_rawshake.o \ + include/libkeccak/libkeccak_spec_sha3.o include/libkeccak/libkeccak_state_copy.o include/libkeccak/libkeccak_state_create.o include/libkeccak/libkeccak_state_destroy.o include/libkeccak/libkeccak_state_duplicate.o \ + include/libkeccak/libkeccak_state_fast_destroy.o include/libkeccak/libkeccak_state_fast_free.o include/libkeccak/libkeccak_state_free.o include/libkeccak/libkeccak_state_initialise.o include/libkeccak/libkeccak_state_marshal.o \ + include/libkeccak/libkeccak_state_reset.o include/libkeccak/libkeccak_state_unmarshal.o include/libkeccak/libkeccak_state_wipe.o include/libkeccak/libkeccak_state_wipe_message.o include/libkeccak/libkeccak_state_wipe_sponge.o \ + include/libkeccak/libkeccak_unhex.o include/libkeccak/libkeccak_zerocopy_chunksize.o \ + include/libsais/libsais.o + +ifeq ($(UNAME_P),x86_64) + ifneq (,$(findstring -DHAVE_AVX2,$(HAVE_FEATURE))) + OBJECTS += include/highwayhash/hh_avx2.o + endif + OBJECTS += include/highwayhash/hh_sse41.o +else ifneq ($($(UNAME_P),aarch64),$($(UNAME_P),arm64)) + OBJECTS += include/highwayhash/hh_neon.o +else + OBJECTS += include/highwayhash/hh_vsx.o +endif + +OBJECTS += astro_aarch64.o astrobwtv3.o exports.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +.PHONY: clean + +clean: + $(RM) $(TARGET) $(OBJECTS) diff --git a/src/Native/libdero/astro_aarch64.cpp b/src/Native/libdero/astro_aarch64.cpp new file mode 100644 index 0000000000..bc321664e1 --- /dev/null +++ b/src/Native/libdero/astro_aarch64.cpp @@ -0,0 +1,4281 @@ + +#if defined(__aarch64__) + +#include "astro_aarch64.hpp" + +inline uint8x16_t binary_not(uint8x16_t data) { + //chunk[i] = ~chunk[i]; + // also maybe + //const uint8x16_t ones = vdupq_n_u8(0xFF); + // return vbicq_u8(data, ones); + return vmvnq_u8(data); +} + +inline uint8x16_t rotate_bits(uint8x16_t data, int rotation) { + //chunk[i] = std::rotl(chunk[i], 3); + //chunk[i] = (chunk[i] << 3) | (chunk[i] >> (8 - 3)); + rotation %= 8; + // TODO: Find out how we can make clang tell us the different between ARMv8.2a (which compiles here) and ARMv8-a (which does not) + //return vorrq_u8(vshlq_n_u8(data, rotation), vshrq_n_u8(data, 8 - rotation)); + auto rotation_amounts = vdupq_n_u8(rotation); + return vorrq_u8(vshlq_u8(data, rotation_amounts), vshlq_u8(data, vsubq_u8(rotation_amounts, vdupq_n_u8(8)))); +} + +inline uint8x16_t rotate_and_xor(uint8x16_t left_side, int rotation) { + //chunk[i] ^= (chunk[i] << 2) | (chunk[i] >> (8 - 2)); + //rotation = rotation % 8; + //rotation %= 8; + //uint8x16_t rotated = vorrq_u8(vshlq_n_u8(left_side, rotation), vshrq_n_u8(left_side, 8 - rotation)); + + // Perform XOR with original data + return veorq_u8(left_side, rotate_bits(left_side, rotation)); +} + + +inline uint8x16_t add_with_self(uint8x16_t a) { + //chunk[i] += chunk[i]; + return vaddq_u8(a, a); +} + +inline uint8x16_t mul_with_self(uint8x16_t a) { + + return vmulq_u8(a, a); +} + +inline uint8x16_t and_vectors(uint8x16_t a, uint8x16_t b) { + //chunk[i] = chunk[i] & chunk[pos2]; + // Perform XOR with original data + return vandq_u8(a, b); +} + +inline uint8x16_t xor_vectors(uint8x16_t a, uint8x16_t b) { + //chunk[i] ^= chunk[pos2]; + // Perform XOR with original data + return veorq_u8(a, b); +} + +inline uint8x16_t xor_with_bittable(uint8x16_t a) { + + //auto count = vcntq_u8(a); + // Perform XOR with original data + return veorq_u8(a, vcntq_u8(a)); +} + +inline uint8x16_t reverse_vector(uint8x16_t data) { + return vrbitq_u8(data); +} + +/* +uint8x16_t shift_left_by_int_with_and(uint8x16_t data, int andint) { + //chunk[i] = chunk[i] << (chunk[i] & 3); + // Note: This is signed! + int8x16_t anded = vandq_s8(data, vdupq_n_u8(andint)); + return vshlq_u8(data, anded); +} +*/ + +inline uint8x16_t shift_left_by_int_with_and(uint8x16_t data, int andint) { + //chunk[i] = chunk[i] << (chunk[i] & 3); + // Note: This is signed! + //int8x16_t anded = vandq_s8(data, vdupq_n_u8(andint)); + return vshlq_u8(data, vandq_s8(data, vdupq_n_u8(andint))); +} + +/* +uint8x16_t shift_right_by_int_with_and(uint8x16_t data, int andint) { + //chunk[i] = chunk[i] >> (chunk[i] & 3); + // Note: This is signed! + int8x16_t anded = vandq_s8(data, vdupq_n_u8(andint)); + + // We can negate and left-shift to effectively do a right-shift; + int8x16_t negated = vqnegq_s8(anded); + return vshlq_u8(data, negated); +} +*/ + +inline uint8x16_t shift_right_by_int_with_and(uint8x16_t data, int andint) { + //chunk[i] = chunk[i] >> (chunk[i] & 3); + return vshlq_u8(data, vqnegq_s8(vandq_s8(data, vdupq_n_u8(andint)))); +} + +inline uint8x16_t subtract_xored(uint8x16_t data, int xor_value) { + //chunk[i] -= (chunk[i] ^ 97); + //auto xored = veorq_u8(data, vdupq_n_u8(xor_value)); + return vsubq_u8(data, veorq_u8(data, vdupq_n_u8(xor_value))); +} + +inline uint8x16_t rotate_by_self(uint8x16_t data) { + + // see rotate_by_self + //(chunk[i] << (chunk[i] % 8)) | (chunk[i] >> (8 - (chunk[i] % 8))); + // Shift left by the remainder of each element divided by 8 + uint8x16_t rotation_amounts = vandq_u8(data, vdupq_n_u8(7)); + + //for(int x = 0; x < 16; x++) { + // printf("mod: %02x\n", rotation_amounts[x]); + //} + + //uint8x16_t shifted_left = vshlq_u8(data, rotation_amounts); + + + //uint8x16_t right_shift_amounts = vsubq_u8(vandq_u8(data, vdupq_n_u8(7)), vdupq_n_u8(8)); + //uint8x16_t right_shift_amounts = vsubq_u8(rotation_amounts, vdupq_n_u8(8)); + + // Perform the right shift using left shift with negative amounts + //return vshlq_u8(data, right_shift_amounts); + // Shift right by (8 - remainder) of each element + + + // Combine the shifted results using bitwise OR + //return vorrq_u8(shifted_left, vshlq_u8(data, right_shift_amounts)); + return vorrq_u8(vshlq_u8(data, rotation_amounts), vshlq_u8(data, vsubq_u8(rotation_amounts, vdupq_n_u8(8)))); + + //chunk[i] = (chunk[i] << (chunk[i] % 8)) | (chunk[i] >> (8 - (chunk[i] % 8))); + //chunk[i] = std::rotl(chunk[i], chunk[i]); + //return rotate_bits_by_vector(data); +} + +uint32_t branchComputeCPU_aarch64(RC4_KEY key, unsigned char *sData) +{ + unsigned char aarchFixup[256]; + uint64_t lhash = hash_64_fnv1a_256(sData); + uint64_t prev_lhash = lhash; + + unsigned char *prev_chunk; + unsigned char *chunk; + + uint64_t tries = 0; + bool isSame = false; + + unsigned char opt[256]; + + while (true) + { + tries++; + uint64_t random_switcher = prev_lhash ^ lhash ^ tries; + + unsigned char op = static_cast(random_switcher); + + unsigned char pos1 = static_cast(random_switcher >> 8); + unsigned char pos2 = static_cast(random_switcher >> 16); + + if (pos1 > pos2) + { + std::swap(pos1, pos2); + } + + if (pos2 - pos1 > 32) + { + pos2 = pos1 + ((pos2 - pos1) & 0x1f); + } + + chunk = &sData[(tries - 1) * 256]; + + if (tries == 1) { + prev_chunk = chunk; + } else { + prev_chunk = &sData[(tries - 2) * 256]; + } + + memcpy(chunk, prev_chunk, 256); + + memcpy(aarchFixup, &chunk[pos2], 16); + switch (op) + { + case 0: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = (chunk[i] << 5) | (chunk[i] >> (8 - 5)); // rotate bits by 5 + chunk[i] *= chunk[i]; // * + chunk[i] = (chunk[i] << (chunk[i] % 8)) | (chunk[i] >> (8 - (chunk[i] % 8))); // rotate bits by random + + // INSERT_RANDOM_CODE_END + unsigned char t1 = chunk[pos1]; + unsigned char t2 = chunk[pos2]; + chunk[pos1] = reverse8(t2); + chunk[pos2] = reverse8(t1); + } + break; + case 1: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_left_by_int_with_and(data, 3); + data = rotate_bits(data, 1); + data = and_vectors(data, p2vec); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 2: + { + opt[op] = true; + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = reverse_vector(data); + data = shift_left_by_int_with_and(data, 3); + data = xor_with_bittable(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 3: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = rotate_bits(data, 3); + data = xor_vectors(data, p2vec); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 4: + { + opt[op] = true; + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = shift_right_by_int_with_and(data, 3); + data = rotate_by_self(data); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 5: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = xor_vectors(data, p2vec); + data = shift_left_by_int_with_and(data, 3); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 6: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_left_by_int_with_and(data, 3); + data = rotate_bits(data, 3); + data = binary_not(data); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 7: + { + opt[op] = true; + memcpy(aarchFixup, &chunk[pos2], 16); + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + // Load 16 bytes (128 bits) of data from chunk + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = rotate_by_self(data); + data = xor_with_bittable(data); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 8: + { + opt[op] = true; + memcpy(aarchFixup, &chunk[pos2], 16); + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + // Load 16 bytes (128 bits) of data from chunk + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = rotate_bits(data, 2); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 9: + { + opt[op] = true; + memcpy(aarchFixup, &chunk[pos2], 16); + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + + for (int i = pos1; i < pos2; i += 16) + { + // Load 16 bytes (128 bits) of data from chunk + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = rotate_and_xor(data, 4); + data = shift_right_by_int_with_and(data, 3); + data = rotate_and_xor(data, 2); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 10: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = mul_with_self(data); + data = rotate_bits(data, 3); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 11: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 6); + data = and_vectors(data, p2vec); + data = rotate_by_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 12: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = mul_with_self(data); + data = rotate_and_xor(data, 2); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 13: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 1); + data = xor_vectors(data, p2vec); + data = shift_right_by_int_with_and(data, 3); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 14: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = shift_left_by_int_with_and(data, 3); + data = mul_with_self(data); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 15: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = shift_left_by_int_with_and(data, 3); + data = and_vectors(data, p2vec); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 16: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = mul_with_self(data); + data = rotate_bits(data, 1); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 17: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = mul_with_self(data); + data = rotate_bits(data, 5); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 18: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 19: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = subtract_xored(data, 97); + data = rotate_bits(data, 5); + data = shift_left_by_int_with_and(data, 3); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 20: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = xor_vectors(data, p2vec); + data = reverse_vector(data); + data = rotate_and_xor(data, 2); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 21: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 1); + data = xor_vectors(data, p2vec); + data = add_with_self(data); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 22: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_left_by_int_with_and(data, 3); + data = reverse_vector(data); + data = mul_with_self(data); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 23: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 4); + data = xor_with_bittable(data); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 24: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = shift_right_by_int_with_and(data, 3); + data = rotate_and_xor(data, 4); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 25: + opt[op] = true; + for (int i = pos1; i < pos2; i += 16) + { + // Load 16 bytes (128 bits) of data from chunk + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = rotate_bits(data, 3); + data = rotate_by_self(data); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + break; + case 26: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = mul_with_self(data); + data = xor_with_bittable(data); + data = add_with_self(data); + data = reverse_vector(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 27: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = and_vectors(data, p2vec); + data = rotate_and_xor(data, 4); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 28: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_left_by_int_with_and(data, 3); + data = add_with_self(data); + data = add_with_self(data); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 29: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = mul_with_self(data); + data = xor_vectors(data, p2vec); + data = shift_right_by_int_with_and(data, 3); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 30: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = rotate_and_xor(data, 4); + data = rotate_bits(data, 5); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 31: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = rotate_and_xor(data, 2); + data = shift_left_by_int_with_and(data, 3); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 32: + { + opt[op] = true; + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = reverse_vector(data); + data = rotate_bits(data, 3); + data = rotate_and_xor(data, 2); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 33: + opt[op] = true; + memcpy(aarchFixup, &chunk[pos2], 16); + for (int i = pos1; i < pos2; i += 16) + { + // Load 16 bytes (128 bits) of data from chunk + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = rotate_and_xor(data, 4); + data = reverse_vector(data); + data = vmulq_u8(data, data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + break; + case 34: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = subtract_xored(data, 97); + data = shift_left_by_int_with_and(data, 3); + data = shift_left_by_int_with_and(data, 3); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 35: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = binary_not(data); + data = rotate_bits(data, 1); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 36: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = rotate_bits(data, 1); + data = rotate_and_xor(data, 2); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 37: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = shift_right_by_int_with_and(data, 3); + data = shift_right_by_int_with_and(data, 3); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 38: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = rotate_bits(data, 3); + data = xor_with_bittable(data); + data = rotate_by_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 39: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = xor_vectors(data, p2vec); + data = shift_right_by_int_with_and(data, 3); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 40: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = xor_vectors(data, p2vec); + data = xor_with_bittable(data); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 41: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = subtract_xored(data, 97); + data = rotate_bits(data, 3); + data = rotate_and_xor(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 42: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 4); + data = rotate_and_xor(data, 2); + data = rotate_by_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 43: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = add_with_self(data); + data = and_vectors(data, p2vec); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 44: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = xor_with_bittable(data); + data = rotate_bits(data, 3); + data = rotate_by_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 45: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 2); + data = and_vectors(data, p2vec); + data = xor_with_bittable(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 46: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = add_with_self(data); + data = rotate_bits(data, 5); + data = rotate_and_xor(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 47: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = and_vectors(data, p2vec); + data = rotate_bits(data, 5); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 48: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 49: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = add_with_self(data); + data = reverse_vector(data); + data = rotate_and_xor(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 50: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = rotate_bits(data, 3); + data = add_with_self(data); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 51: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = rotate_and_xor(data, 4); + data = rotate_and_xor(data, 4); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 52: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = shift_right_by_int_with_and(data, 3); + data = binary_not(data); + data = xor_with_bittable(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 53: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = xor_with_bittable(data); + data = rotate_and_xor(data, 4); + data = rotate_and_xor(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 54: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 55: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = rotate_and_xor(data, 4); + data = rotate_and_xor(data, 4); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 56: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = mul_with_self(data); + data = binary_not(data); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 57: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = reverse_vector(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 58: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = rotate_and_xor(data, 2); + data = and_vectors(data, p2vec); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 59: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 1); + data = mul_with_self(data); + data = rotate_by_self(data); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 60: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = binary_not(data); + data = mul_with_self(data); + data = rotate_bits(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 61: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 62: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = binary_not(data); + data = rotate_and_xor(data, 2); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 63: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = xor_with_bittable(data); + data = subtract_xored(data, 97); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 64: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = reverse_vector(data); + data = rotate_and_xor(data, 4); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 65: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 66: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = reverse_vector(data); + data = rotate_and_xor(data, 4); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 67: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 1); + data = xor_with_bittable(data); + data = rotate_and_xor(data, 2); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 68: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = binary_not(data); + data = rotate_and_xor(data, 4); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 69: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = mul_with_self(data); + data = reverse_vector(data); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 70: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = mul_with_self(data); + data = shift_right_by_int_with_and(data, 3); + data = rotate_and_xor(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 71: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = binary_not(data); + data = mul_with_self(data); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 72: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = xor_with_bittable(data); + data = xor_vectors(data, p2vec); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 73: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = reverse_vector(data); + data = rotate_bits(data, 5); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 74: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = mul_with_self(data); + data = rotate_bits(data, 3); + data = reverse_vector(data); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 75: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = mul_with_self(data); + data = xor_with_bittable(data); + data = and_vectors(data, p2vec); + data = rotate_and_xor(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 76: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = rotate_and_xor(data, 2); + data = rotate_bits(data, 5); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 77: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 3); + data = add_with_self(data); + data = shift_left_by_int_with_and(data, 3); + data = xor_with_bittable(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 78: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = reverse_vector(data); + data = mul_with_self(data); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 79: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = rotate_and_xor(data, 2); + data = add_with_self(data); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 80: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = shift_left_by_int_with_and(data, 3); + data = add_with_self(data); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 81: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = shift_left_by_int_with_and(data, 3); + data = rotate_by_self(data); + data = xor_with_bittable(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 82: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 83: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_left_by_int_with_and(data, 3); + data = reverse_vector(data); + data = rotate_bits(data, 3); + data = reverse_vector(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 84: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = subtract_xored(data, 97); + data = rotate_bits(data, 1); + data = shift_left_by_int_with_and(data, 3); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 85: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = xor_vectors(data, p2vec); + data = rotate_by_self(data); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 86: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = rotate_by_self(data); + data = rotate_and_xor(data, 4); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 87: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = rotate_bits(data, 3); + data = rotate_and_xor(data, 4); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 88: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = rotate_bits(data, 1); + data = mul_with_self(data); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 89: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = mul_with_self(data); + data = binary_not(data); + data = rotate_and_xor(data, 2); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 90: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = rotate_bits(data, 6); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 91: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = and_vectors(data, p2vec); + data = rotate_and_xor(data, 4); + data = reverse_vector(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 92: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = binary_not(data); + data = xor_with_bittable(data); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 93: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = mul_with_self(data); + data = and_vectors(data, p2vec); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 94: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 1); + data = rotate_by_self(data); + data = and_vectors(data, p2vec); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 95: + { + opt[op] = true; + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t vec = vld1q_u8(&chunk[i]); + // Shift the vector elements to the left by one position + uint8x16_t shifted_left = vshlq_n_u8(vec, 1); + uint8x16_t shifted_right = vshrq_n_u8(vec, 8 - 1); + uint8x16_t rotated = vorrq_u8(shifted_left, shifted_right); + uint8x16_t data = binary_not(rotated); + //vmvnq_u8(rotated); + uint8x16_t shifted_a = rotate_bits(data, 10); + vst1q_u8(&chunk[i], shifted_a); + } + // memcpy(&chunk[pos2], aarchFixup, + // (pos2-pos1)%16); + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 96: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = rotate_and_xor(data, 2); + data = xor_with_bittable(data); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 97: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 1); + data = shift_left_by_int_with_and(data, 3); + data = xor_with_bittable(data); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 98: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = shift_left_by_int_with_and(data, 3); + data = shift_right_by_int_with_and(data, 3); + data = rotate_and_xor(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 99: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = subtract_xored(data, 97); + data = reverse_vector(data); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 100: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = shift_left_by_int_with_and(data, 3); + data = reverse_vector(data); + data = xor_with_bittable(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 101: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = xor_with_bittable(data); + data = shift_right_by_int_with_and(data, 3); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 102: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 3); + data = subtract_xored(data, 97); + data = add_with_self(data); + data = rotate_bits(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 103: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 1); + data = reverse_vector(data); + data = xor_vectors(data, p2vec); + data = rotate_by_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 104: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = xor_with_bittable(data); + data = rotate_bits(data, 5); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 105: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_left_by_int_with_and(data, 3); + data = rotate_bits(data, 3); + data = rotate_by_self(data); + data = rotate_and_xor(data, 2); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 106: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = rotate_and_xor(data, 4); + data = rotate_bits(data, 1); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 107: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = rotate_and_xor(data, 2); + data = rotate_bits(data, 6); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 108: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = binary_not(data); + data = and_vectors(data, p2vec); + data = rotate_and_xor(data, 2); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 109: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = mul_with_self(data); + data = rotate_by_self(data); + data = xor_vectors(data, p2vec); + data = rotate_and_xor(data, 2); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 110: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = rotate_and_xor(data, 2); + data = rotate_and_xor(data, 2); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 111: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = mul_with_self(data); + data = reverse_vector(data); + data = mul_with_self(data); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 112: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 3); + data = binary_not(data); + data = rotate_bits(data, 5); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 113: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 6); + data = xor_with_bittable(data); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 114: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 1); + data = reverse_vector(data); + data = rotate_by_self(data); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 115: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = rotate_bits(data, 5); + data = and_vectors(data, p2vec); + data = rotate_bits(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 116: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = xor_vectors(data, p2vec); + data = xor_with_bittable(data); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 117: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_left_by_int_with_and(data, 3); + data = rotate_bits(data, 3); + data = shift_left_by_int_with_and(data, 3); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 118: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = add_with_self(data); + data = shift_left_by_int_with_and(data, 3); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 119: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = rotate_and_xor(data, 2); + data = binary_not(data); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 120: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = mul_with_self(data); + data = xor_vectors(data, p2vec); + data = reverse_vector(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 121: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = add_with_self(data); + data = xor_with_bittable(data); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 122: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = rotate_by_self(data); + data = rotate_bits(data, 5); + data = data = rotate_and_xor(data, 2); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 123: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = binary_not(data); + data = rotate_bits(data, 6); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 124: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = rotate_and_xor(data, 2); + data = xor_vectors(data, p2vec); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 125: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = rotate_and_xor(data, 2); + data = add_with_self(data); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 126: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 1); + data = reverse_vector(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 127: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_left_by_int_with_and(data, 3); + data = mul_with_self(data); + data = and_vectors(data, p2vec); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 128: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = rotate_and_xor(data, 2); + data = rotate_and_xor(data, 2); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 129: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = xor_with_bittable(data); + data = xor_with_bittable(data); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 130: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = rotate_by_self(data); + data = rotate_bits(data, 1); + data = rotate_and_xor(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 131: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = subtract_xored(data, 97); + data = rotate_bits(data, 1); + data = xor_with_bittable(data); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 132: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = reverse_vector(data); + data = rotate_bits(data, 5); + data = rotate_and_xor(data, 2); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 133: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = rotate_bits(data, 5); + data = rotate_and_xor(data, 2); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 134: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = rotate_and_xor(data, 4); + data = rotate_bits(data, 1); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 135: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = rotate_and_xor(data, 2); + data = add_with_self(data); + data = reverse_vector(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 136: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = subtract_xored(data, 97); + data = xor_vectors(data, p2vec); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 137: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = shift_right_by_int_with_and(data, 3); + data = reverse_vector(data); + data = rotate_by_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 138: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = xor_vectors(data, p2vec); + data = add_with_self(data); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 139: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = rotate_bits(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 140: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 1); + data = rotate_and_xor(data, 2); + data = xor_vectors(data, p2vec); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 141: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 1); + data = subtract_xored(data, 97); + data = xor_with_bittable(data); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 142: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = rotate_bits(data, 5); + data = reverse_vector(data); + data = rotate_and_xor(data, 2); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 143: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = rotate_bits(data, 3); + data = shift_right_by_int_with_and(data, 3); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 144: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = shift_left_by_int_with_and(data, 3); + data = binary_not(data); + data = rotate_by_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 145: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = rotate_and_xor(data, 4); + data = rotate_and_xor(data, 2); + data = rotate_and_xor(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 146: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = shift_left_by_int_with_and(data, 3); + data = and_vectors(data, p2vec); + data = xor_with_bittable(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 147: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = shift_left_by_int_with_and(data, 3); + data = rotate_and_xor(data, 4); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 148: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = rotate_bits(data, 5); + data = shift_left_by_int_with_and(data, 3); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 149: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = reverse_vector(data); + data = subtract_xored(data, 97); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 150: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_left_by_int_with_and(data, 3); + data = shift_left_by_int_with_and(data, 3); + data = shift_left_by_int_with_and(data, 3); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 151: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = shift_left_by_int_with_and(data, 3); + data = mul_with_self(data); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 152: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = binary_not(data); + data = shift_left_by_int_with_and(data, 3); + data = rotate_and_xor(data, 2); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 153: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 154: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = binary_not(data); + data = xor_vectors(data, p2vec); + data = xor_with_bittable(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 155: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = subtract_xored(data, 97); + data = xor_vectors(data, p2vec); + data = xor_with_bittable(data); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 156: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = shift_right_by_int_with_and(data, 3); + data = rotate_bits(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 157: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = shift_left_by_int_with_and(data, 3); + data = rotate_by_self(data); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 158: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = rotate_bits(data, 3); + data = add_with_self(data); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 159: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = subtract_xored(data, 97); + data = xor_vectors(data, p2vec); + data = rotate_by_self(data); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 160: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = reverse_vector(data); + data = rotate_bits(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 161: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = xor_vectors(data, p2vec); + data = rotate_bits(data, 5); + data = rotate_by_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 162: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = mul_with_self(data); + data = reverse_vector(data); + data = rotate_and_xor(data, 2); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 163: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_left_by_int_with_and(data, 3); + data = subtract_xored(data, 97); + data = rotate_and_xor(data, 4); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 164: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = mul_with_self(data); + data = xor_with_bittable(data); + data = subtract_xored(data, 97); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 165: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = xor_vectors(data, p2vec); + data = shift_left_by_int_with_and(data, 3); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 166: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 3); + data = add_with_self(data); + data = rotate_and_xor(data, 2); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 167: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = mul_with_self(data); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 168: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = and_vectors(data, p2vec); + data = rotate_by_self(data); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 169: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 1); + data = shift_left_by_int_with_and(data, 3); + data = rotate_and_xor(data, 4); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 170: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = subtract_xored(data, 97); + data = reverse_vector(data); + data = subtract_xored(data, 97); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 171: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 3); + data = subtract_xored(data, 97); + data = xor_with_bittable(data); + data = reverse_vector(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 172: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = subtract_xored(data, 97); + data = shift_left_by_int_with_and(data, 3); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 173: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = shift_left_by_int_with_and(data, 3); + data = mul_with_self(data); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 174: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = rotate_by_self(data); + data = xor_with_bittable(data); + data = xor_with_bittable(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 175: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 3); + data = subtract_xored(data, 97); + data = mul_with_self(data); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 176: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = mul_with_self(data); + data = xor_vectors(data, p2vec); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 177: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = rotate_and_xor(data, 2); + data = rotate_and_xor(data, 2); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 178: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = add_with_self(data); + data = binary_not(data); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 179: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = add_with_self(data); + data = shift_right_by_int_with_and(data, 3); + data = reverse_vector(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 180: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = rotate_and_xor(data, 4); + data = xor_vectors(data, p2vec); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 181: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = shift_left_by_int_with_and(data, 3); + data = rotate_and_xor(data, 2); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 182: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = rotate_bits(data, 6); + data = rotate_and_xor(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 183: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = subtract_xored(data, 97); + data = subtract_xored(data, 97); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 184: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_left_by_int_with_and(data, 3); + data = mul_with_self(data); + data = rotate_bits(data, 5); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 185: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = rotate_and_xor(data, 4); + data = rotate_bits(data, 5); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 186: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = rotate_and_xor(data, 4); + data = subtract_xored(data, 97); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 187: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = binary_not(data); + data = add_with_self(data); + data = rotate_bits(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 188: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = xor_with_bittable(data); + data = rotate_and_xor(data, 4); + data = rotate_and_xor(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 189: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = rotate_and_xor(data, 4); + data = xor_vectors(data, p2vec); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 190: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = shift_right_by_int_with_and(data, 3); + data = and_vectors(data, p2vec); + data = rotate_and_xor(data, 2); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 191: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = rotate_bits(data, 3); + data = rotate_by_self(data); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 192: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = shift_left_by_int_with_and(data, 3); + data = add_with_self(data); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 193: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = shift_left_by_int_with_and(data, 3); + data = rotate_by_self(data); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 194: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = rotate_by_self(data); + data = shift_left_by_int_with_and(data, 3); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 195: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = rotate_and_xor(data, 2); + data = xor_vectors(data, p2vec); + data = rotate_and_xor(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 196: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 3); + data = reverse_vector(data); + data = shift_left_by_int_with_and(data, 3); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 197: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = rotate_by_self(data); + data = mul_with_self(data); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 198: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = shift_right_by_int_with_and(data, 3); + data = reverse_vector(data); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 199: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = add_with_self(data); + data = mul_with_self(data); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 200: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = xor_with_bittable(data); + data = reverse_vector(data); + data = reverse_vector(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 201: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 3); + data = rotate_and_xor(data, 2); + data = rotate_and_xor(data, 4); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 202: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = binary_not(data); + data = rotate_by_self(data); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 203: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = and_vectors(data, p2vec); + data = rotate_bits(data, 1); + data = rotate_by_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 204: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = rotate_and_xor(data, 2); + data = rotate_by_self(data); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 205: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = rotate_and_xor(data, 4); + data = shift_left_by_int_with_and(data, 3); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 206: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = reverse_vector(data); + data = reverse_vector(data); + data = xor_with_bittable(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 207: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_with_bittable(data); + data = xor_with_bittable(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 208: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = add_with_self(data); + data = shift_right_by_int_with_and(data, 3); + data = rotate_bits(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 209: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = reverse_vector(data); + data = xor_with_bittable(data); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 210: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = rotate_by_self(data); + data = rotate_bits(data, 5); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 211: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = add_with_self(data); + data = subtract_xored(data, 97); + data = rotate_by_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 212: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = rotate_and_xor(data, 2); + data = xor_vectors(data, p2vec); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 213: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = shift_left_by_int_with_and(data, 3); + data = rotate_bits(data, 3); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 214: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = subtract_xored(data, 97); + data = shift_right_by_int_with_and(data, 3); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 215: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = and_vectors(data, p2vec); + data = shift_left_by_int_with_and(data, 3); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 216: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_by_self(data); + data = binary_not(data); + data = subtract_xored(data, 97); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 217: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = add_with_self(data); + data = rotate_bits(data, 1); + data = rotate_and_xor(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 218: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = binary_not(data); + data = mul_with_self(data); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 219: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = rotate_bits(data, 3); + data = and_vectors(data, p2vec); + data = reverse_vector(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 220: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 1); + data = shift_left_by_int_with_and(data, 3); + data = reverse_vector(data); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 221: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = xor_vectors(data, p2vec); + data = binary_not(data); + data = reverse_vector(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 222: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = shift_right_by_int_with_and(data, 3); + data = shift_left_by_int_with_and(data, 3); + data = xor_vectors(data, p2vec); + data = mul_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 223: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 3); + data = xor_vectors(data, p2vec); + data = rotate_by_self(data); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 224: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = rotate_bits(data, 4); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 225: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = shift_right_by_int_with_and(data, 3); + data = reverse_vector(data); + data = rotate_bits(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 226: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = subtract_xored(data, 97); + data = mul_with_self(data); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 227: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = shift_left_by_int_with_and(data, 3); + data = subtract_xored(data, 97); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 228: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = shift_right_by_int_with_and(data, 3); + data = add_with_self(data); + data = xor_with_bittable(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 229: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 3); + data = rotate_by_self(data); + data = rotate_and_xor(data, 2); + data = xor_with_bittable(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 230: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = mul_with_self(data); + data = and_vectors(data, p2vec); + data = rotate_by_self(data); + data = rotate_by_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 231: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 3); + data = shift_right_by_int_with_and(data, 3); + data = xor_vectors(data, p2vec); + data = reverse_vector(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 232: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = mul_with_self(data); + data = mul_with_self(data); + data = rotate_and_xor(data, 4); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 233: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 1); + data = xor_with_bittable(data); + data = rotate_bits(data, 3); + data = xor_with_bittable(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 234: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = mul_with_self(data); + data = shift_right_by_int_with_and(data, 3); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 235: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 2); + data = mul_with_self(data); + data = rotate_bits(data, 3); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 236: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = xor_vectors(data, p2vec); + data = add_with_self(data); + data = and_vectors(data, p2vec); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 237: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = shift_left_by_int_with_and(data, 3); + data = rotate_and_xor(data, 2); + data = rotate_bits(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 238: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = add_with_self(data); + data = rotate_bits(data, 3); + data = subtract_xored(data, 97); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 239: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 6); + data = mul_with_self(data); + data = and_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 240: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = add_with_self(data); + data = and_vectors(data, p2vec); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 241: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_and_xor(data, 4); + data = xor_with_bittable(data); + data = xor_vectors(data, p2vec); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 242: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = add_with_self(data); + data = subtract_xored(data, 97); + data = xor_vectors(data, p2vec); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 243: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = rotate_and_xor(data, 2); + data = xor_with_bittable(data); + data = rotate_bits(data, 1); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 244: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = rotate_and_xor(data, 2); + data = reverse_vector(data); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 245: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = subtract_xored(data, 97); + data = rotate_bits(data, 5); + data = rotate_and_xor(data, 2); + data = shift_right_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 246: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = rotate_bits(data, 1); + data = shift_right_by_int_with_and(data, 3); + data = add_with_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 247: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = rotate_bits(data, 5); + data = rotate_and_xor(data, 2); + data = rotate_bits(data, 5); + data = binary_not(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 248: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = binary_not(data); + data = subtract_xored(data, 97); + data = xor_with_bittable(data); + data = rotate_bits(data, 5); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 249: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = rotate_and_xor(data, 4); + data = rotate_and_xor(data, 4); + data = rotate_by_self(data); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 250: + { + opt[op] = true; + uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = and_vectors(data, p2vec); + data = rotate_by_self(data); + data = xor_with_bittable(data); + data = rotate_and_xor(data, 4); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 251: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = add_with_self(data); + data = xor_with_bittable(data); + data = reverse_vector(data); + data = rotate_and_xor(data, 2); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 252: + { + opt[op] = true; + // uint8x16_t p2vec = vdupq_n_u8(chunk[pos2]); + for (int i = pos1; i < pos2; i += 16) + { + uint8x16_t data = vld1q_u8(&chunk[i]); + data = reverse_vector(data); + data = rotate_and_xor(data, 4); + data = rotate_and_xor(data, 2); + data = shift_left_by_int_with_and(data, 3); + vst1q_u8(&chunk[i], data); + } + memcpy(&chunk[pos2], aarchFixup, 16); + } + break; + case 253: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = (chunk[i] << 3) | (chunk[i] >> (8 - 3)); // rotate bits by 3 + chunk[i] ^= (chunk[i] << 2) | (chunk[i] >> (8 - 2)); // rotate bits by 2 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = (chunk[i] << 3) | (chunk[i] >> (8 - 3)); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + + prev_lhash = lhash + prev_lhash; + lhash = XXHash64::hash(chunk, pos2,0); + //lhash = XXH64(chunk, pos2, 0); + //lhash = XXH3_64bits(chunk, pos2); + } + break; + case 254: + case 255: + RC4_set_key(&key, 256, chunk); +// chunk = highwayhash.Sum(chunk[:], chunk[:]) +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= static_cast(std::bitset<8>(chunk[i]).count()); // ones count bits + chunk[i] = (chunk[i] << 3) | (chunk[i] >> (8 - 3)); // rotate bits by 3 + chunk[i] ^= (chunk[i] << 2) | (chunk[i] >> (8 - 2)); // rotate bits by 2 + chunk[i] = (chunk[i] << 3) | (chunk[i] >> (8 - 3)); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + } + break; + default: + break; + } + + __builtin_prefetch(chunk,0,3); + // __builtin_prefetch(chunk+64,0,3); + // __builtin_prefetch(chunk+128,0,3); + __builtin_prefetch(chunk+192,0,3); + + unsigned char A = (chunk[pos1] - chunk[pos2]); + A = (256 + (A % 256)) % 256; + + if (A < 0x10) + { // 6.25 % probability + prev_lhash = lhash + prev_lhash; + lhash = XXHash64::hash(chunk, pos2, 0); + } + + if (A < 0x20) + { // 12.5 % probability + prev_lhash = lhash + prev_lhash; + lhash = hash_64_fnv1a(chunk, pos2); + } + + if (A < 0x30) + { // 18.75 % probability + prev_lhash = lhash + prev_lhash; + HH_ALIGNAS(16) + const highwayhash::HH_U64 key2[2] = {tries, prev_lhash}; + lhash = highwayhash::SipHash(key2, (char*)chunk, pos2); // more deviations + } + + if (A <= 0x40) + { // 25% probablility + RC4(&key, 256, chunk, chunk); + } + + chunk[255] = chunk[255] ^ chunk[pos1] ^ chunk[pos2]; + + if (tries > 260 + 16 || (sData[(tries-1)*256+255] >= 0xf0 && tries > 260)) + { + break; + } + } + uint32_t data_len = static_cast((tries - 4) * 256 + (((static_cast(chunk[253]) << 8) | static_cast(chunk[254])) & 0x3ff)); + + return data_len; +} + +#endif \ No newline at end of file diff --git a/src/Native/libdero/astro_aarch64.hpp b/src/Native/libdero/astro_aarch64.hpp new file mode 100644 index 0000000000..c7dc52828a --- /dev/null +++ b/src/Native/libdero/astro_aarch64.hpp @@ -0,0 +1,14 @@ +#if defined(__aarch64__) +#include + +#include + +#include "include/fnv1a.h" +#include "include/xxhash64.h" +#include "include/highwayhash/sip_hash.h" +#include "astrobwtv3.h" + +#include "include/lookup.h" + +uint32_t branchComputeCPU_aarch64(RC4_KEY key, unsigned char *sData); +#endif \ No newline at end of file diff --git a/src/Native/libdero/astrobwtv3.cpp b/src/Native/libdero/astrobwtv3.cpp new file mode 100644 index 0000000000..d3aafc5c11 --- /dev/null +++ b/src/Native/libdero/astrobwtv3.cpp @@ -0,0 +1,7288 @@ +#include "include/endian.hpp" +#include "include/fnv1a.h" +#include "include/xxhash64.h" +#include "astrobwtv3.h" +#include "include/highwayhash/sip_hash.h" +#include "include/lookup.h" + +#if defined(__x86_64__) + #include + #include +#endif +#if defined(__aarch64__) + #include "astro_aarch64.hpp" +#endif + +void hashSHA256(SHA256_CTX &sha256, const unsigned char *input, unsigned char *digest, unsigned long inputSize) +{ + SHA256_Init(&sha256); + SHA256_Update(&sha256, input, inputSize); + SHA256_Final(digest, &sha256); +} + +void AstroBWTv3(const unsigned char *input, int inputLen, unsigned char *outputhash) +{ + try + { + //void * ctx = libsais_create_ctx(); + unsigned char sData[MAX_LENGTH+64]; + SHA256_CTX sha256; + unsigned char salsaInput[256] = {0}; + ucstk::Salsa20 salsa20; + RC4_KEY key = {}; + int32_t sa[MAX_LENGTH]; + //int bA[256]; + //int bB[256*256]; + unsigned char sHash[32]; + uint32_t data_len; + + std::fill_n(sData + 256, 64, 0); + memset(sData + 256, 0, 64); + + __builtin_prefetch(&sData[256], 1, 3); + __builtin_prefetch(&sData[256+64], 1, 3); + __builtin_prefetch(&sData[256+128], 1, 3); + __builtin_prefetch(&sData[256+192], 1, 3); + + hashSHA256(sha256, input, &sData[320], inputLen); + salsa20.setKey(&sData[320]); + salsa20.setIv(&sData[256]); + + __builtin_prefetch(&sData, 1, 3); + __builtin_prefetch(&sData[64], 1, 3); + __builtin_prefetch(&sData[128], 1, 3); + __builtin_prefetch(&sData[192], 1, 3); + + salsa20.processBytes(salsaInput, sData, 256); + + //__builtin_prefetch(&key + 8, 1, 3); + //__builtin_prefetch(&key + 8+64, 1, 3); + //__builtin_prefetch(&key + 8+128, 1, 3); + //__builtin_prefetch(&key + 8+192, 1, 3); + + RC4_set_key(&key, 256, sData); + RC4(&key, 256, sData, sData); + + #if defined(__AVX2__) + //data_len = branchComputeCPU_avx2(key, sData); + data_len = wolfCompute(key, sData); + #elif defined(__aarch64__) + data_len = branchComputeCPU_aarch64(key, sData); + #else + data_len = branchComputeCPU(key, sData); + #endif + + // divsufsort(sData, sa, data_len, bA, bB); + libsais(sData, sa, data_len, MAX_LENGTH-data_len, NULL); + + if (littleEndian()) + { + unsigned char *B = reinterpret_cast(sa); + hashSHA256(sha256, B, sHash, data_len*4); + // sHash = nHash; + } + else + { + unsigned char *s = new unsigned char[MAX_LENGTH * 4]; + for (int i = 0; i < data_len; i++) + { + s[i << 1] = htonl(sa[i]); + } + hashSHA256(sha256, s, sHash, data_len*4); + // sHash = nHash; + delete[] s; + } + memcpy(outputhash, sHash, 32); + // memset(outputhash, 0xFF, 32); + } + catch (const std::exception &ex) + { + // recover(outputhash); + std::cerr << ex.what() << std::endl; + } +} + +uint32_t branchComputeCPU(RC4_KEY key, unsigned char *sData) +{ + uint64_t lhash = hash_64_fnv1a_256(sData); + uint64_t prev_lhash = lhash; + + unsigned char *prev_chunk; + unsigned char *chunk; + + uint64_t tries = 0; + + while (true) + { + tries++; + uint64_t random_switcher = prev_lhash ^ lhash ^ tries; + + unsigned char op = static_cast(random_switcher); + + unsigned char pos1 = static_cast(random_switcher >> 8); + unsigned char pos2 = static_cast(random_switcher >> 16); + + if (pos1 > pos2) + { + std::swap(pos1, pos2); + } + + if (pos2 - pos1 > 32) + { + pos2 = pos1 + ((pos2 - pos1) & 0x1f); + } + + chunk = &sData[(tries - 1) * 256]; + + if (tries == 1) { + prev_chunk = chunk; + } else { + prev_chunk = &sData[(tries - 2) * 256]; + } + + memcpy(chunk, prev_chunk, 256); + + switch (op) + { + case 0: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] *= chunk[i]; // * + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + + // INSERT_RANDOM_CODE_END + unsigned char t1 = chunk[pos1]; + unsigned char t2 = chunk[pos2]; + chunk[pos1] = reverse8(t2); + chunk[pos2] = reverse8(t1); + } + break; + case 1: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 2: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + // INSERT_RANDOM_CODE_END + } + break; + case 3: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 4: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 5: + { +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + + // INSERT_RANDOM_CODE_END + } + } + break; + case 6: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] -= (chunk[i] ^ 97); // XOR and - + + // INSERT_RANDOM_CODE_END + } + break; + case 7: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 8: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = rl8(chunk[i], 10); // rotate bits by 5 + // chunk[i] = rl8(chunk[i], 5);// rotate bits by 5 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 9: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + // INSERT_RANDOM_CODE_END + } + break; + case 10: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] *= chunk[i]; // * + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 11: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 6); // rotate bits by 1 + // chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 12: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] *= chunk[i]; // * + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 13: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 14: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] *= chunk[i]; // * + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 15: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 16: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] *= chunk[i]; // * + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 17: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] *= chunk[i]; // * + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 18: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 9); // rotate bits by 3 + // chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 19: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 20: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + // INSERT_RANDOM_CODE_END + } + break; + case 21: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 22: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] *= chunk[i]; // * + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 23: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 4); // rotate bits by 3 + // chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 24: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 25: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 26: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] *= chunk[i]; // * + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] += chunk[i]; // + + chunk[i] = reverse8(chunk[i]); // reverse bits + // INSERT_RANDOM_CODE_END + } + break; + case 27: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 28: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] += chunk[i]; // + + chunk[i] += chunk[i]; // + + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 29: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] *= chunk[i]; // * + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 30: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 31: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 32: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + // INSERT_RANDOM_CODE_END + } + break; + case 33: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 34: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 35: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] ^= chunk[pos2]; // XOR + // INSERT_RANDOM_CODE_END + } + break; + case 36: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 37: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 38: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 39: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 40: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= chunk[pos2]; // XOR + // INSERT_RANDOM_CODE_END + } + break; + case 41: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 42: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 4); // rotate bits by 1 + // chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 43: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 44: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 45: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 10); // rotate bits by 5 + // chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + // INSERT_RANDOM_CODE_END + } + break; + case 46: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] += chunk[i]; // + + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 47: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 48: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // chunk[i] = ~chunk[i]; // binary NOT operator + // chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 49: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] += chunk[i]; // + + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 50: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] += chunk[i]; // + + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 51: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 52: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + // INSERT_RANDOM_CODE_END + } + break; + case 53: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 54: + +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= chunk[pos2]; // XOR + // chunk[i] = ~chunk[i]; // binary NOT operator + // chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + + break; + case 55: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 56: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] *= chunk[i]; // * + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 57: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = rl8(chunk[i], 8); // rotate bits by 5 + // chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = reverse8(chunk[i]); // reverse bits + // INSERT_RANDOM_CODE_END + } + break; + case 58: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 59: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] *= chunk[i]; // * + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 60: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] *= chunk[i]; // * + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + } + break; + case 61: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = rl8(chunk[i], 8); // rotate bits by 3 + // chunk[i] = rl8(chunk[i], 5);// rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 62: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 63: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 64: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 65: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 8); // rotate bits by 5 + // chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 66: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 67: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 68: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= chunk[pos2]; // XOR + // INSERT_RANDOM_CODE_END + } + break; + case 69: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] *= chunk[i]; // * + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 70: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] *= chunk[i]; // * + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 71: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] *= chunk[i]; // * + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 72: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 73: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 74: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] *= chunk[i]; // * + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 75: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] *= chunk[i]; // * + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 76: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 77: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + // INSERT_RANDOM_CODE_END + } + break; + case 78: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] *= chunk[i]; // * + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 79: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] += chunk[i]; // + + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 80: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 81: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + // INSERT_RANDOM_CODE_END + } + break; + case 82: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + // chunk[i] = ~chunk[i]; // binary NOT operator + // chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 83: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = reverse8(chunk[i]); // reverse bits + // INSERT_RANDOM_CODE_END + } + break; + case 84: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 85: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 86: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 87: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 88: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] *= chunk[i]; // * + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 89: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] *= chunk[i]; // * + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + // INSERT_RANDOM_CODE_END + } + break; + case 90: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = rl8(chunk[i], 6); // rotate bits by 5 + // chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 91: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = reverse8(chunk[i]); // reverse bits + // INSERT_RANDOM_CODE_END + } + break; + case 92: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 93: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] *= chunk[i]; // * + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 94: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 95: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = rl8(chunk[i], 10); // rotate bits by 5 + // chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 96: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 97: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 98: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 99: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 100: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + // INSERT_RANDOM_CODE_END + } + break; + case 101: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 102: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] += chunk[i]; // + + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + } + break; + case 103: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 104: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 105: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + // INSERT_RANDOM_CODE_END + } + break; + case 106: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 107: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], 6); // rotate bits by 5 + // chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 108: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + // INSERT_RANDOM_CODE_END + } + break; + case 109: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] *= chunk[i]; // * + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + // INSERT_RANDOM_CODE_END + } + break; + case 110: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 111: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] *= chunk[i]; // * + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] *= chunk[i]; // * + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 112: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 113: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 6); // rotate bits by 5 + // chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 114: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 115: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + } + break; + case 116: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 117: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 118: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 119: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] ^= chunk[pos2]; // XOR + // INSERT_RANDOM_CODE_END + } + break; + case 120: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] *= chunk[i]; // * + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = reverse8(chunk[i]); // reverse bits + // INSERT_RANDOM_CODE_END + } + break; + case 121: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] += chunk[i]; // + + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 122: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + // INSERT_RANDOM_CODE_END + } + break; + case 123: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = rl8(chunk[i], 6); // rotate bits by 3 + // chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + } + break; + case 124: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 125: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 126: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 9); // rotate bits by 3 + // chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = reverse8(chunk[i]); // reverse bits + // INSERT_RANDOM_CODE_END + } + break; + case 127: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] *= chunk[i]; // * + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] ^= chunk[pos2]; // XOR + // INSERT_RANDOM_CODE_END + } + break; + case 128: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 129: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 130: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 131: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 132: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + // INSERT_RANDOM_CODE_END + } + break; + case 133: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 134: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 135: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] += chunk[i]; // + + chunk[i] = reverse8(chunk[i]); // reverse bits + // INSERT_RANDOM_CODE_END + } + break; + case 136: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 137: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 138: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] += chunk[i]; // + + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 139: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 8); // rotate bits by 5 + // chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + } + break; + case 140: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 141: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 142: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + // INSERT_RANDOM_CODE_END + } + break; + case 143: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 144: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 145: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 146: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + // INSERT_RANDOM_CODE_END + } + break; + case 147: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 148: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 149: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 150: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 151: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] *= chunk[i]; // * + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 152: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + // INSERT_RANDOM_CODE_END + } + break; + case 153: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 4); // rotate bits by 1 + // chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // chunk[i] = ~chunk[i]; // binary NOT operator + // chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 154: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + // INSERT_RANDOM_CODE_END + } + break; + case 155: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= chunk[pos2]; // XOR + // INSERT_RANDOM_CODE_END + } + break; + case 156: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = rl8(chunk[i], 4); // rotate bits by 3 + // chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 157: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 158: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] += chunk[i]; // + + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 159: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= chunk[pos2]; // XOR + // INSERT_RANDOM_CODE_END + } + break; + case 160: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = rl8(chunk[i], 4); // rotate bits by 1 + // chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + } + break; + case 161: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 162: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] *= chunk[i]; // * + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 163: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 164: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] *= chunk[i]; // * + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 165: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 166: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] += chunk[i]; // + + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 167: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + // chunk[i] = ~chunk[i]; // binary NOT operator + // chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] *= chunk[i]; // * + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 168: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 169: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 170: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 171: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = reverse8(chunk[i]); // reverse bits + // INSERT_RANDOM_CODE_END + } + break; + case 172: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 173: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] *= chunk[i]; // * + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 174: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + // INSERT_RANDOM_CODE_END + } + break; + case 175: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] *= chunk[i]; // * + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 176: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] *= chunk[i]; // * + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 177: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 178: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] += chunk[i]; // + + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 179: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = reverse8(chunk[i]); // reverse bits + // INSERT_RANDOM_CODE_END + } + break; + case 180: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 181: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 182: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], 6); // rotate bits by 1 + // chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 183: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 184: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] *= chunk[i]; // * + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] ^= chunk[pos2]; // XOR + // INSERT_RANDOM_CODE_END + } + break; + case 185: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 186: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 187: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] += chunk[i]; // + + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + } + break; + case 188: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 189: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 190: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + // INSERT_RANDOM_CODE_END + } + break; + case 191: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 192: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] += chunk[i]; // + + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 193: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 194: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 195: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 196: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 197: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] *= chunk[i]; // * + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 198: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 199: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] += chunk[i]; // + + chunk[i] *= chunk[i]; // * + chunk[i] ^= chunk[pos2]; // XOR + // INSERT_RANDOM_CODE_END + } + break; + case 200: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = reverse8(chunk[i]); // reverse bits + // INSERT_RANDOM_CODE_END + } + break; + case 201: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 202: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 203: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 204: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= chunk[pos2]; // XOR + // INSERT_RANDOM_CODE_END + } + break; + case 205: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 206: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + // INSERT_RANDOM_CODE_END + } + break; + case 207: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 8); // rotate bits by 5 + // chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + // INSERT_RANDOM_CODE_END + } + break; + case 208: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + } + break; + case 209: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 210: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 211: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] += chunk[i]; // + + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 212: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] ^= chunk[pos2]; // XOR + // INSERT_RANDOM_CODE_END + } + break; + case 213: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 214: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 215: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 216: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 217: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] += chunk[i]; // + + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 218: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] *= chunk[i]; // * + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 219: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = reverse8(chunk[i]); // reverse bits + // INSERT_RANDOM_CODE_END + } + break; + case 220: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 221: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = reverse8(chunk[i]); // reverse bits + // INSERT_RANDOM_CODE_END + } + break; + case 222: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] *= chunk[i]; // * + // INSERT_RANDOM_CODE_END + } + break; + case 223: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 224: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], 4); // rotate bits by 1 + // chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // + } + break; + case 225: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + } + break; + case 226: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] *= chunk[i]; // * + chunk[i] ^= chunk[pos2]; // XOR + // INSERT_RANDOM_CODE_END + } + break; + case 227: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 228: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] += chunk[i]; // + + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + // INSERT_RANDOM_CODE_END + } + break; + case 229: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + // INSERT_RANDOM_CODE_END + } + break; + case 230: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] *= chunk[i]; // * + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 231: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = reverse8(chunk[i]); // reverse bits + // INSERT_RANDOM_CODE_END + } + break; + case 232: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] *= chunk[i]; // * + chunk[i] *= chunk[i]; // * + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 233: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + // INSERT_RANDOM_CODE_END + } + break; + case 234: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] *= chunk[i]; // * + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] ^= chunk[pos2]; // XOR + // INSERT_RANDOM_CODE_END + } + break; + case 235: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] *= chunk[i]; // * + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 236: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 237: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + } + break; + case 238: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] += chunk[i]; // + + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 239: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 6); // rotate bits by 5 + // chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] *= chunk[i]; // * + chunk[i] = chunk[i] & chunk[pos2]; // AND + // INSERT_RANDOM_CODE_END + } + break; + case 240: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 241: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 242: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] += chunk[i]; // + + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] ^= chunk[pos2]; // XOR + // INSERT_RANDOM_CODE_END + } + break; + case 243: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 244: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 245: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + // INSERT_RANDOM_CODE_END + } + break; + case 246: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] += chunk[i]; // + + // INSERT_RANDOM_CODE_END + } + break; + case 247: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + chunk[i] = ~chunk[i]; // binary NOT operator + // INSERT_RANDOM_CODE_END + } + break; + case 248: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = ~chunk[i]; // binary NOT operator + chunk[i] -= (chunk[i] ^ 97); // XOR and - + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 249: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 250: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = chunk[i] & chunk[pos2]; // AND + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 251: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] += chunk[i]; // + + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + // INSERT_RANDOM_CODE_END + } + break; + case 252: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = chunk[i] << (chunk[i] & 3); // shift left + // INSERT_RANDOM_CODE_END + } + break; + case 253: +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + + prev_lhash = lhash + prev_lhash; + lhash = XXHash64::hash(chunk, pos2,0); + } + break; + case 254: + case 255: + RC4_set_key(&key, 256, chunk); +// chunk = highwayhash.Sum(chunk[:], chunk[:]) +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= static_cast(std::bitset<8>(chunk[i]).count()); // ones count bits + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + } + break; + default: + break; + } + + unsigned char A = (chunk[pos1] - chunk[pos2]); + A = (256 + (A % 256)) % 256; + + if (A < 0x10) + { // 6.25 % probability + __builtin_prefetch(chunk, 0, 0); + prev_lhash = lhash + prev_lhash; + lhash = XXHash64::hash(chunk, pos2, 0); + } + + if (A < 0x20) + { // 12.5 % probability + __builtin_prefetch(chunk, 0, 0); + prev_lhash = lhash + prev_lhash; + lhash = hash_64_fnv1a(chunk, pos2); + } + + if (A < 0x30) + { // 18.75 % probability + __builtin_prefetch(chunk, 0, 0); + prev_lhash = lhash + prev_lhash; + HH_ALIGNAS(16) + const highwayhash::HH_U64 key2[2] = {tries, prev_lhash}; + lhash = highwayhash::SipHash(key2, (char*)chunk, pos2); // more deviations + } + + if (A <= 0x40) + { // 25% probablility + //__builtin_prefetch(&key, 0, 0); + RC4(&key, 256, chunk, chunk); + } + + chunk[255] = chunk[255] ^ chunk[pos1] ^ chunk[pos2]; + + prefetch(chunk, 256, 1); + memcpy(&sData[(tries - 1) * 256], chunk, 256); + + if (tries > 260 + 16 || (chunk[255] >= 0xf0 && tries > 260)) + { + break; + } + } + uint32_t data_len = static_cast((tries - 4) * 256 + (((static_cast(chunk[253]) << 8) | static_cast(chunk[254])) & 0x3ff)); + + return data_len; +} + +#if defined(__AVX2__) + +uint32_t branchComputeCPU_avx2(RC4_KEY key, unsigned char *sData) +{ + uint64_t lhash = hash_64_fnv1a_256(sData); + uint64_t prev_lhash = lhash; + + unsigned char *prev_chunk; + unsigned char *chunk; + + uint64_t tries = 0; + + while (true) + { + tries++; + uint64_t random_switcher = prev_lhash ^ lhash ^ tries; + + unsigned char op = static_cast(random_switcher); + + unsigned char pos1 = static_cast(random_switcher >> 8); + unsigned char pos2 = static_cast(random_switcher >> 16); + + if (pos1 > pos2) + { + std::swap(pos1, pos2); + } + + if (pos2 - pos1 > 32) + { + pos2 = pos1 + ((pos2 - pos1) & 0x1f); + } + + chunk = &sData[(tries - 1) * 256]; + + if (tries == 1) { + prev_chunk = chunk; + } else { + prev_chunk = &sData[(tries - 2) * 256]; + + __builtin_prefetch(prev_chunk,0,3); + __builtin_prefetch(prev_chunk+64,0,3); + __builtin_prefetch(prev_chunk+128,0,3); + __builtin_prefetch(prev_chunk+192,0,3); + + // Calculate the start and end blocks + int start_block = 0; + int end_block = pos1 / 16; + + // Copy the blocks before pos1 + for (int i = start_block; i < end_block; i++) { + __m128i prev_data = _mm_loadu_si128((__m128i*)&prev_chunk[i * 16]); + _mm_storeu_si128((__m128i*)&chunk[i * 16], prev_data); + } + + // Copy the remaining bytes before pos1 + for (int i = end_block * 16; i < pos1; i++) { + chunk[i] = prev_chunk[i]; + } + + // Calculate the start and end blocks + start_block = (pos2 + 15) / 16; + end_block = 16; + + // Copy the blocks after pos2 + for (int i = start_block; i < end_block; i++) { + __m128i prev_data = _mm_loadu_si128((__m128i*)&prev_chunk[i * 16]); + _mm_storeu_si128((__m128i*)&chunk[i * 16], prev_data); + } + + // Copy the remaining bytes after pos2 + for (int i = pos2; i < start_block * 16; i++) { + chunk[i] = prev_chunk[i]; + } + } + + __builtin_prefetch(&chunk[pos1],1,3); + + switch(op) { + case 0: + // #pragma GCC unroll 16 + { + // Load 32 bytes of prev_chunk starting from i into an AVX2 256-bit register + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + __m256i pop = popcnt256_epi8(data); + + data = _mm256_xor_si256(data,pop); + + // Rotate left by 5 + data = _mm256_rol_epi8(data, 5); + + // Full 16-bit multiplication + data = _mm256_mul_epi8(data, data); + data = _mm256_rolv_epi8(data, data); + + // Write results to workerData + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + if ((pos2-pos1)%2 == 1) { + unsigned char t1 = chunk[pos1]; + unsigned char t2 = chunk[pos2]; + chunk[pos1] = reverse8(t2); + chunk[pos2] = reverse8(t1); + } + break; + case 1: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + __m256i shift = _mm256_and_si256(data, vec_3); + data = _mm256_sllv_epi8(data, shift); + data = _mm256_rol_epi8(data,1); + data = _mm256_and_si256(data, _mm256_set1_epi8(prev_chunk[pos2])); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 2: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data,pop); + data = _mm256_reverse_epi8(data); + + __m256i shift = _mm256_and_si256(data, vec_3); + data = _mm256_sllv_epi8(data, shift); + + pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data,pop); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 3: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data,_mm256_add_epi8(data,vec_3)); + data = _mm256_xor_si256(data,_mm256_set1_epi8(chunk[pos2])); + data = _mm256_rol_epi8(data,1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 4: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_srlv_epi8(data,_mm256_and_si256(data,vec_3)); + data = _mm256_rolv_epi8(data,data); + data = _mm256_sub_epi8(data,_mm256_xor_si256(data,_mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 5: + { + // Load 32 bytes of prev_chunk starting from i into an AVX2 256-bit register + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data,pop); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_sllv_epi8(data,_mm256_and_si256(data,vec_3)); + data = _mm256_srlv_epi8(data,_mm256_and_si256(data,vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + + break; + case 6: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sllv_epi8(data,_mm256_and_si256(data,vec_3)); + data = _mm256_rol_epi8(data, 3); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + __m256i x = _mm256_xor_si256(data,_mm256_set1_epi8(97)); + data = _mm256_sub_epi8(data,x); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 7: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data);; + data = _mm256_rolv_epi8(data, data); + + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data,pop); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 8: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_rol_epi8(data,2); + data = _mm256_sllv_epi8(data,_mm256_and_si256(data,vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 9: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data,4)); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data,vec_3)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data,2)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 10: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_mul_epi8(data, data); + data = _mm256_rol_epi8(data, 3); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 11: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 6); + data = _mm256_and_si256(data,_mm256_set1_epi8(chunk[pos2])); + data = _mm256_rolv_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 12: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data,2)); + data = _mm256_mul_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data,2)); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 13: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + data = _mm256_xor_si256(data,_mm256_set1_epi8(chunk[pos2])); + data = _mm256_srlv_epi8(data,_mm256_and_si256(data,vec_3)); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 14: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data,_mm256_and_si256(data,vec_3)); + data = _mm256_sllv_epi8(data,_mm256_and_si256(data,vec_3)); + data = _mm256_mul_epi8(data, data); + data = _mm256_sllv_epi8(data,_mm256_and_si256(data,vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 15: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data,2)); + data = _mm256_sllv_epi8(data,_mm256_and_si256(data,vec_3)); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_sub_epi8(data,_mm256_xor_si256(data,_mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 16: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data,4)); + data = _mm256_mul_epi8(data, data); + data = _mm256_rol_epi8(data,1); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 17: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_mul_epi8(data, data); + data = _mm256_rol_epi8(data,5); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 18: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_rol_epi8(data, 1); + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 19: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sub_epi8(data,_mm256_xor_si256(data,_mm256_set1_epi8(97))); + data = _mm256_rol_epi8(data, 5); + data = _mm256_sllv_epi8(data,_mm256_and_si256(data,vec_3)); + data = _mm256_add_epi8(data, data);;; + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 20: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 21: + + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_add_epi8(data, data); + data = _mm256_and_si256(data,_mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 22: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sllv_epi8(data, _mm256_and_si256(data,vec_3)); + data = _mm256_reverse_epi8(data); + data = _mm256_mul_epi8(data,data); + data = _mm256_rol_epi8(data,1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 23: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 4); + data = _mm256_xor_si256(data,popcnt256_epi8(data)); + data = _mm256_and_si256(data,_mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 24: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data,vec_3)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 25: + #pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = prev_chunk[i] ^ (unsigned char)bitTable[prev_chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + chunk[i] -= (chunk[i] ^ 97); // XOR and - + // INSERT_RANDOM_CODE_END + } + break; + case 26: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_mul_epi8(data, data); + data = _mm256_xor_si256(data,popcnt256_epi8(data)); + data = _mm256_add_epi8(data, data); + data = _mm256_reverse_epi8(data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 27: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_and_si256(data,_mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 28: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sllv_epi8(data, _mm256_and_si256(data,vec_3)); + data = _mm256_add_epi8(data, data); + data = _mm256_add_epi8(data, data); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 29: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_mul_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data,vec_3)); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 30: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_rol_epi8(data, 5); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data,vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 31: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data,vec_3)); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 32: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_reverse_epi8(data); + data = _mm256_rol_epi8(data, 3); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 33: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_reverse_epi8(data); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 34: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data,vec_3)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data,vec_3)); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 35: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_rol_epi8(data, 1); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 36: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_rol_epi8(data, 1); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 37: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data,vec_3)); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data,vec_3)); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 38: + #pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = prev_chunk[i] >> (prev_chunk[i] & 3); // shift right + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 39: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data,vec_3)); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 40: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 41: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_rol_epi8(data, 3); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 42: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 4); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_rolv_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 43: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_add_epi8(data, data); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 44: + #pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = prev_chunk[i] ^ (unsigned char)bitTable[prev_chunk[i]]; // ones count bits + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 45: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 2); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 46: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_add_epi8(data, data); + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 47: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rol_epi8(data, 5); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data,vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 48: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 49: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_add_epi8(data, data); + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 50: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_reverse_epi8(data); + data = _mm256_rol_epi8(data, 3); + data = _mm256_add_epi8(data, data); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 51: + #pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = prev_chunk[i] ^ chunk[pos2]; // XOR + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 52: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data,vec_3)); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 53: + #pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = prev_chunk[i]*2; // + + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 54: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + + break; + case 55: + #pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(prev_chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 56: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_mul_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 57: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_reverse_epi8(data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 58: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 59: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + data = _mm256_mul_epi8(data, data); + data = _mm256_rolv_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 60: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_mul_epi8(data, data); + data = _mm256_rol_epi8(data, 3); + + #ifdef _WIN32 + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + #else + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + #endif + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + + break; + case 61: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 62: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 63: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + + break; + case 64: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 65: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 66: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 67: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 68: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 69: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_mul_epi8(data, data); + data = _mm256_reverse_epi8(data); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 70: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_mul_epi8(data, data); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 71: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_mul_epi8(data, data); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 72: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 73: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_reverse_epi8(data); + data = _mm256_rol_epi8(data, 5); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 74: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_mul_epi8(data, data); + data = _mm256_rol_epi8(data, 3); + data = _mm256_reverse_epi8(data); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 75: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_mul_epi8(data, data); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 76: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_rol_epi8(data, 5); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 77: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 3); + data = _mm256_add_epi8(data, data); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 78: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_reverse_epi8(data); + data = _mm256_mul_epi8(data, data); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 79: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_add_epi8(data, data); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 80: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_add_epi8(data, data); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 81: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_rolv_epi8(data, data); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 82: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 83: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_reverse_epi8(data); + data = _mm256_rol_epi8(data, 3); + data = _mm256_reverse_epi8(data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 84: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_rol_epi8(data, 1); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 85: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rolv_epi8(data, data); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 86: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_rolv_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 87: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_rol_epi8(data, 3); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 88: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_rol_epi8(data, 1); + data = _mm256_mul_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 89: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_mul_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 90: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_reverse_epi8(data); + data = _mm256_rol_epi8(data, 6); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 91: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_reverse_epi8(data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 92: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 93: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_mul_epi8(data, data); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 94: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + data = _mm256_rolv_epi8(data, data); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 95: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_rol_epi8(data, 2); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 96: + #pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = prev_chunk[i] ^ rl8(prev_chunk[i], 2); // rotate bits by 2 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] = rl8(chunk[i], 1); // rotate bits by 1 + // INSERT_RANDOM_CODE_END + } + break; + case 97: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 98: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 99: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_reverse_epi8(data); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 100: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 101: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 102: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 3); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_add_epi8(data, data); + data = _mm256_rol_epi8(data, 3); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 103: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rolv_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 104: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_rol_epi8(data, 5); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 105: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_rol_epi8(data, 3); + data = _mm256_rolv_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 106: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_rol_epi8(data, 1); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 107: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_rol_epi8(data, 6); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 108: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 109: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_mul_epi8(data, data); + data = _mm256_rolv_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 110: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 111: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_mul_epi8(data, data); + data = _mm256_reverse_epi8(data); + data = _mm256_mul_epi8(data, data); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 112: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 3); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_rol_epi8(data, 5); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 113: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 6); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 114: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + data = _mm256_reverse_epi8(data); + data = _mm256_rolv_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 115: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_rol_epi8(data, 5); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rol_epi8(data, 3); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 116: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 117: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_rol_epi8(data, 3); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 118: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_add_epi8(data, data); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 119: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 120: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_mul_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_reverse_epi8(data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 121: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_add_epi8(data, data); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 122: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_rolv_epi8(data, data); + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 123: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_rol_epi8(data, 6); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 124: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 125: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_add_epi8(data, data); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 126: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + data = _mm256_reverse_epi8(data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 127: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_mul_epi8(data, data); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 128: + #pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(prev_chunk[i], prev_chunk[i]); // rotate bits by random + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] = rl8(chunk[i], 5); // rotate bits by 5 + // INSERT_RANDOM_CODE_END + } + break; + case 129: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 130: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_rolv_epi8(data, data); + data = _mm256_rol_epi8(data, 1); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 131: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_rol_epi8(data, 1); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 132: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_reverse_epi8(data); + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 133: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 134: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_rol_epi8(data, 1); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 135: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_add_epi8(data, data); + data = _mm256_reverse_epi8(data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 136: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 137: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_reverse_epi8(data); + data = _mm256_rolv_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 138: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_add_epi8(data, data); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 139: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_rol_epi8(data, 3); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 140: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 141: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 142: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rol_epi8(data, 5); + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 143: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rol_epi8(data, 3); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 144: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_rolv_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 145: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 146: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 147: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 148: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rol_epi8(data, 5); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 149: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_reverse_epi8(data); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 150: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 151: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_mul_epi8(data, data); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 152: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 153: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 4); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 154: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 155: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 156: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_rol_epi8(data, 4); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 157: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_rolv_epi8(data, data); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 158: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_rol_epi8(data, 3); + data = _mm256_add_epi8(data, data); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 159: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rolv_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 160: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_reverse_epi8(data); + data = _mm256_rol_epi8(data, 4); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 161: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rol_epi8(data, 5); + data = _mm256_rolv_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 162: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_mul_epi8(data, data); + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 163: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 164: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_mul_epi8(data, data); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 165: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 166: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 3); + data = _mm256_add_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 167: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_mul_epi8(data, data); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 168: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rolv_epi8(data, data); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 169: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 170: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_reverse_epi8(data); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 171: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 3); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_reverse_epi8(data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 172: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 173: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_mul_epi8(data, data); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 174: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_rolv_epi8(data, data); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 175: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 3); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_mul_epi8(data, data); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 176: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_mul_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 177: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 178: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_add_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 179: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_add_epi8(data, data); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_reverse_epi8(data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 180: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 181: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 182: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rol_epi8(data, 6); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 183: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 184: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_mul_epi8(data, data); + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 185: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_rol_epi8(data, 5); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 186: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 187: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_add_epi8(data, data); + data = _mm256_rol_epi8(data, 3); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 188: + #pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] ^= rl8(prev_chunk[i], 4); // rotate bits by 4 + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; // ones count bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + // INSERT_RANDOM_CODE_END + } + break; + case 189: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 190: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 191: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_rol_epi8(data, 3); + data = _mm256_rolv_epi8(data, data); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 192: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_add_epi8(data, data); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 193: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_rolv_epi8(data, data); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 194: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rolv_epi8(data, data); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 195: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 196: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 3); + data = _mm256_reverse_epi8(data); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 197: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_rolv_epi8(data, data); + data = _mm256_mul_epi8(data, data); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 198: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_reverse_epi8(data); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 199: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_add_epi8(data, data); + data = _mm256_mul_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 200: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_reverse_epi8(data); + data = _mm256_reverse_epi8(data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 201: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 3); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 202: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_rolv_epi8(data, data); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 203: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rol_epi8(data, 1); + data = _mm256_rolv_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 204: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_rolv_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 205: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 206: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_reverse_epi8(data); + data = _mm256_reverse_epi8(data); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 207: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 208: + #pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = prev_chunk[i]*2; // + + chunk[i] += chunk[i]; // + + chunk[i] = chunk[i] >> (chunk[i] & 3); // shift right + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + } + break; + case 209: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_reverse_epi8(data); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 210: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_rolv_epi8(data, data); + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 211: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_add_epi8(data, data); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_rolv_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 212: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + // data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + // data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 213: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_rol_epi8(data, 3); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 214: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 215: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 216: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rolv_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 217: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_add_epi8(data, data); + data = _mm256_rol_epi8(data, 1); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 218: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_mul_epi8(data, data); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 219: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_rol_epi8(data, 3); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_reverse_epi8(data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 220: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_reverse_epi8(data); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 221: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_reverse_epi8(data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 222: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_mul_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 223: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 3); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rolv_epi8(data, data); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 224: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_rol_epi8(data, 4); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 225: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_reverse_epi8(data); + data = _mm256_rol_epi8(data, 3); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 226: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_reverse_epi8(data); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_mul_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 227: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 228: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_add_epi8(data, data); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 229: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 3); + data = _mm256_rolv_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 230: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_mul_epi8(data, data); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rolv_epi8(data, data); + data = _mm256_rolv_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 231: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 3); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_reverse_epi8(data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 232: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_mul_epi8(data, data); + data = _mm256_mul_epi8(data, data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 233: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 1); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_rol_epi8(data, 3); + pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 234: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_mul_epi8(data, data); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 235: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_mul_epi8(data, data); + data = _mm256_rol_epi8(data, 3); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 236: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_add_epi8(data, data); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 237: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_rol_epi8(data, 3); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 238: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_add_epi8(data, data); + data = _mm256_rol_epi8(data, 3); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 239: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 6); + data = _mm256_mul_epi8(data, data); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 240: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_add_epi8(data, data); + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 241: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 242: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_add_epi8(data, data); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 243: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_rol_epi8(data, 1); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 244: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_reverse_epi8(data); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 245: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 246: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + data = _mm256_rol_epi8(data, 1); + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + data = _mm256_add_epi8(data, data); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 247: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_rol_epi8(data, 5); + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 248: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_rol_epi8(data, 5); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 249: + #pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = reverse8(prev_chunk[i]); // reverse bits + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] ^= rl8(chunk[i], 4); // rotate bits by 4 + chunk[i] = rl8(chunk[i], chunk[i]); // rotate bits by random + // INSERT_RANDOM_CODE_END + } + break; + case 250: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + data = _mm256_rolv_epi8(data, data); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 251: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_add_epi8(data, data); + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 252: + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + data = _mm256_reverse_epi8(data); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + case 253: + { + std::copy(&prev_chunk[pos1], &prev_chunk[pos2], &chunk[pos1]); + #pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + + prev_lhash = lhash + prev_lhash; + lhash = XXHash64::hash(chunk, pos2,0); + } + break; + } + case 254: + case 255: + RC4_set_key(&key, 256, prev_chunk); + + { + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + __m256i pop = popcnt256_epi8(data); + data = _mm256_xor_si256(data, pop); + data = _mm256_rol_epi8(data, 3); + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + data = _mm256_rol_epi8(data, 3); + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + } + break; + default: + break; + } + + __builtin_prefetch(chunk,0,3); + // __builtin_prefetch(chunk+64,0,3); + // __builtin_prefetch(chunk+128,0,3); + __builtin_prefetch(chunk+192,0,3); + + unsigned char A = (chunk[pos1] - chunk[pos2]); + A = (256 + (A % 256)) % 256; + + if (A < 0x10) + { // 6.25 % probability + prev_lhash = lhash + prev_lhash; + lhash = XXHash64::hash(chunk, pos2, 0); + } + + if (A < 0x20) + { // 12.5 % probability + prev_lhash = lhash + prev_lhash; + lhash = hash_64_fnv1a(chunk, pos2); + } + + if (A < 0x30) + { // 18.75 % probability + prev_lhash = lhash + prev_lhash; + HH_ALIGNAS(16) + const highwayhash::HH_U64 key2[2] = {tries, prev_lhash}; + lhash = highwayhash::SipHash(key2, (char*)chunk, pos2); // more deviations + } + + if (A <= 0x40) + { // 25% probablility + RC4(&key, 256, chunk, chunk); + } + + chunk[255] = chunk[255] ^ chunk[pos1] ^ chunk[pos2]; + + if (tries > 260 + 16 || (sData[(tries-1)*256+255] >= 0xf0 && tries > 260)) + { + break; + } + } + uint32_t data_len = static_cast((tries - 4) * 256 + (((static_cast(chunk[253]) << 8) | static_cast(chunk[254])) & 0x3ff)); + + return data_len; +} + +#endif + +// WOLF CODE + +uint32_t wolfCompute(RC4_KEY key, unsigned char *sData) +{ + uint64_t lhash = hash_64_fnv1a_256(sData); + uint64_t prev_lhash = lhash; + + unsigned char *prev_chunk; + unsigned char *chunk; + + uint64_t tries = 0; + + unsigned char pos1; + unsigned char pos2; + + while (true) + { + tries++; + uint64_t random_switcher = prev_lhash ^ lhash ^ tries; + + unsigned char op = static_cast(random_switcher); + + unsigned char p1 = static_cast(random_switcher >> 8); + unsigned char p2 = static_cast(random_switcher >> 16); + + if (p1 > p2) + { + std::swap(p1, p2); + } + + if (p2 - p1 > 32) + { + p2 = p1 + ((p2 - p1) & 0x1f); + } + + pos1 = p1; + pos2 = p2; + + chunk = &sData[(tries - 1) * 256]; + + if (tries == 1) { + prev_chunk = chunk; + } else { + prev_chunk = &sData[(tries - 2) * 256]; + + #if defined(__AVX2__) + __builtin_prefetch(prev_chunk,0,3); + __builtin_prefetch(prev_chunk+64,0,3); + __builtin_prefetch(prev_chunk+128,0,3); + __builtin_prefetch(prev_chunk+192,0,3); + + // Calculate the start and end blocks + int start_block = 0; + int end_block = pos1 / 16; + + // Copy the blocks before pos1 + for (int i = start_block; i < end_block; i++) { + __m128i prev_data = _mm_loadu_si128((__m128i*)&prev_chunk[i * 16]); + _mm_storeu_si128((__m128i*)&chunk[i * 16], prev_data); + } + + // Copy the remaining bytes before pos1 + for (int i = end_block * 16; i < pos1; i++) { + chunk[i] = prev_chunk[i]; + } + + // Calculate the start and end blocks + start_block = (pos2 + 15) / 16; + end_block = 16; + + // Copy the blocks after pos2 + for (int i = start_block; i < end_block; i++) { + __m128i prev_data = _mm_loadu_si128((__m128i*)&prev_chunk[i * 16]); + _mm_storeu_si128((__m128i*)&chunk[i * 16], prev_data); + } + + // Copy the remaining bytes after pos2 + for (int i = pos2; i < start_block * 16; i++) { + chunk[i] = prev_chunk[i]; + } + #endif + } + + #if defined(__AVX2__) + __builtin_prefetch(&chunk[pos1],1,3); + #else + memcpy(chunk, prev_chunk, 256); + #endif + + uint32_t Opcode = CodeLUT[op]; + + if (op >= 254) { + RC4_set_key(&key, 256, prev_chunk); + } + + #if defined(__AVX2__) + __m256i data = _mm256_loadu_si256((__m256i*)&prev_chunk[pos1]); + __m256i old = data; + + for (int j = 3; j >= 0; --j) + { + uint8_t insn = (Opcode >> (j << 3)) & 0xFF; + switch (insn) + { + case 0: + data = _mm256_add_epi8(data, data); + break; + case 1: + data = _mm256_sub_epi8(data, _mm256_xor_si256(data, _mm256_set1_epi8(97))); + break; + case 2: + data = _mm256_mul_epi8(data, data); + break; + case 3: + data = _mm256_xor_si256(data, _mm256_set1_epi8(chunk[pos2])); + break; + case 4: + data = _mm256_xor_si256(data, _mm256_set1_epi64x(-1LL)); + break; + case 5: + data = _mm256_and_si256(data, _mm256_set1_epi8(chunk[pos2])); + break; + case 6: + data = _mm256_sllv_epi8(data, _mm256_and_si256(data, vec_3)); + break; + case 7: + data = _mm256_srlv_epi8(data, _mm256_and_si256(data, vec_3)); + break; + case 8: + data = _mm256_reverse_epi8(data); + break; + case 9: + data = _mm256_xor_si256(data, popcnt256_epi8(data)); + break; + case 10: + data = _mm256_rolv_epi8(data, data); + break; + case 11: + data = _mm256_rol_epi8(data, 1); + break; + case 12: + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 2)); + break; + case 13: + data = _mm256_rol_epi8(data, 3); + break; + case 14: + data = _mm256_xor_si256(data, _mm256_rol_epi8(data, 4)); + break; + case 15: + data = _mm256_rol_epi8(data, 5); + break; + } + } + + data = _mm256_blendv_epi8(old, data, genMask(pos2-pos1)); + _mm256_storeu_si256((__m256i*)&chunk[pos1], data); + #else +#pragma GCC unroll 32 + for(int i = pos1; i < pos2; ++i) + { + for (int j = 3; j >= 0; --j) + { + uint8_t insn = (Opcode >> (j << 3)) & 0xFF; + switch (insn) + { + case 0: + chunk[i] += chunk[i]; + break; + case 1: + chunk[i] -= (chunk[i] ^ 97); + break; + case 2: + chunk[i] *= chunk[i]; + break; + case 3: + chunk[i] ^= chunk[pos2]; + break; + case 4: + chunk[i] = ~chunk[i]; + break; + case 5: + chunk[i] = chunk[i] & chunk[pos2]; + break; + case 6: + chunk[i] = chunk[i] << (chunk[i] & 3); + break; + case 7: + chunk[i] = chunk[i] >> (chunk[i] & 3); + break; + case 8: + chunk[i] = reverse8(chunk[i]); + break; + case 9: + chunk[i] ^= (unsigned char)bitTable[chunk[i]]; + break; + case 10: + chunk[i] = rl8(chunk[i], chunk[i]); + break; + case 11: + chunk[i] = rl8(chunk[i], 1); + break; + case 12: + chunk[i] ^= rl8(chunk[i], 2); + break; + case 13: + chunk[i] = rl8(chunk[i], 3); + break; + case 14: + chunk[i] ^= rl8(chunk[i], 4); + break; + case 15: + chunk[i] = rl8(chunk[i], 5); + break; + } + } + } + #endif + + if (op == 253) + { + #if defined(__AVX2__) + std::copy(&prev_chunk[pos1], &prev_chunk[pos2], &chunk[pos1]); + #else +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + chunk[i] = prev_chunk[i]; + } + #endif +#pragma GCC unroll 32 + for (int i = pos1; i < pos2; i++) + { + + // INSERT_RANDOM_CODE_START + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + chunk[i] ^= rl8(chunk[i], 2); // rotate bits by 2 + chunk[i] ^= chunk[pos2]; // XOR + chunk[i] = rl8(chunk[i], 3); // rotate bits by 3 + // INSERT_RANDOM_CODE_END + + prev_lhash = lhash + prev_lhash; + lhash = XXHash64::hash(chunk, pos2,0); + } + } + + if (op == 0) { + if ((pos2-pos1)%2 == 1) { + unsigned char t1 = chunk[pos1]; + unsigned char t2 = chunk[pos2]; + chunk[pos1] = reverse8(t2); + chunk[pos2] = reverse8(t1); + } + } + + #if defined(__AVX2__) + __builtin_prefetch(chunk,0,3); + // __builtin_prefetch(chunk+64,0,3); + // __builtin_prefetch(chunk+128,0,3); + __builtin_prefetch(chunk+192,0,3); + #endif + + unsigned char A = (chunk[pos1] - chunk[pos2]); + A = (256 + (A % 256)) % 256; + + if (A < 0x10) + { // 6.25 % probability + prev_lhash = lhash + prev_lhash; + lhash = XXHash64::hash(chunk, pos2, 0); + } + + if (A < 0x20) + { // 12.5 % probability + prev_lhash = lhash + prev_lhash; + lhash = hash_64_fnv1a(chunk, pos2); + } + + if (A < 0x30) + { // 18.75 % probability + prev_lhash = lhash + prev_lhash; + HH_ALIGNAS(16) + const highwayhash::HH_U64 key2[2] = {tries, prev_lhash}; + lhash = highwayhash::SipHash(key2, (char*)chunk, pos2); // more deviations + } + + if (A <= 0x40) + { // 25% probablility + RC4(&key, 256, chunk, chunk); + } + + chunk[255] = chunk[255] ^ chunk[pos1] ^ chunk[pos2]; + + if (tries > 260 + 16 || (sData[(tries-1)*256+255] >= 0xf0 && tries > 260)) + { + break; + } + } + + uint32_t data_len = static_cast((tries - 4) * 256 + (((static_cast(chunk[253]) << 8) | static_cast(chunk[254])) & 0x3ff)); + + return data_len; +} diff --git a/src/Native/libdero/astrobwtv3.h b/src/Native/libdero/astrobwtv3.h new file mode 100644 index 0000000000..28e68c7664 --- /dev/null +++ b/src/Native/libdero/astrobwtv3.h @@ -0,0 +1,402 @@ +/* +Copyright 2024 Cedric CRISPIN (cedric-crispin.com) +Authors: Cedric CRISPIN (cedric.crispin@gmail.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. +*/ +#ifndef ASTROBWTV3_H +#define ASTROBWTV3_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "include/Salsa20.h" +#include +#include + +#ifdef _WIN32 +#include +#include +#else +#include +#endif + +#include "include/libsais/libsais.h" + +#if defined(__x86_64__) + #include "immintrin.h" +#endif +#if defined(__aarch64__) + #include +#endif + +const uint32_t MAX_LENGTH = (256 * 384) - 1; // this is the maximum + +// The base for the following code was contributed by @Wolf9466 on Discord +// Last instruction is a special case, and duplicated. +const uint32_t CodeLUT[256] = +{ + 0x090F020A, 0x060B0500, 0x09080609, 0x0A0D030B, 0x04070A01, 0x09030607, 0x060D0401, 0x000A0904, + 0x040F0F06, 0x030E070C, 0x04020D02, 0x0B0F050A, 0x0C020C04, 0x0B03070F, 0x07060206, 0x0C060501, + 0x0E020B04, 0x03020F04, 0x0E0D0B0F, 0x010F0600, 0x0503080C, 0x0B030005, 0x0608020B, 0x0D0B0905, + 0x00070E0F, 0x090D0A01, 0x02090008, 0x0F050E0F, 0x0600000F, 0x02030700, 0x050E0F06, 0x040C0602, + 0x0C080D0C, 0x0A0E0802, 0x01060601, 0x00040B03, 0x090B0C0B, 0x0A070702, 0x070D090A, 0x0C030705, + 0x0A030903, 0x0F010D0E, 0x0B0D0C0A, 0x05000501, 0x09090D0A, 0x0F0F0509, 0x09000F0E, 0x0F050F06, + 0x0A04040F, 0x0900080E, 0x080D000B, 0x030E0E0F, 0x0A070409, 0x00090E0E, 0x08030404, 0x080E0E0B, + 0x0C02040B, 0x0A0F0D08, 0x080C0500, 0x0B020A04, 0x0304020D, 0x0F060D0F, 0x05040C00, 0x0F090100, + 0x03080E02, 0x0F0D0C02, 0x0C080E0B, 0x0B090C0F, 0x05040E03, 0x00020807, 0x0302070E, 0x0F040206, + 0x08090306, 0x09080F01, 0x020D0805, 0x0209050E, 0x0A0C0F07, 0x0D000609, 0x0A080201, 0x0E0C0002, + 0x0A060005, 0x0E060A09, 0x03040407, 0x06080D08, 0x010B0600, 0x07030A06, 0x0E0A0E04, 0x000D0E00, + 0x0C0B0204, 0x0002040C, 0x080F0B07, 0x09050E08, 0x09040905, 0x0C020500, 0x0B0A0506, 0x0B040F0F, + 0x0C0C090B, 0x0B060907, 0x0E06070E, 0x0E010807, 0x0A060809, 0x07090704, 0x0D01000D, 0x0B08030A, + 0x08090F00, 0x060D0A0C, 0x080E0B02, 0x070C0F0B, 0x0304050C, 0x020A030C, 0x000C0C07, 0x02080207, + 0x0D040F01, 0x0F0B0904, 0x0B080A04, 0x0A0F050D, 0x05030906, 0x060D0605, 0x0700060F, 0x080C0403, + 0x0C020308, 0x07000902, 0x0E0A0F0C, 0x05040D0D, 0x0C0C0304, 0x080C0007, 0x0D0B0F08, 0x06020503, + 0x0A0C0C0F, 0x04090907, 0x070A0B0E, 0x010B0902, 0x05080F0C, 0x030F0C06, 0x040E0B05, 0x070C0008, + 0x0701030F, 0x0F07080A, 0x03030001, 0x0F0D0C0D, 0x0B0C030F, 0x0B010900, 0x050F080C, 0x050D0706, + 0x0A06040A, 0x080E0C0E, 0x05060509, 0x04060E02, 0x050F0601, 0x03080100, 0x06060605, 0x00060206, + 0x0704060C, 0x0B0D0404, 0x0F040309, 0x01030903, 0x07070D0B, 0x07060A0B, 0x090D000B, 0x01030A03, + 0x07080B0D, 0x03030F0A, 0x02080C01, 0x06010E0B, 0x02090104, 0x0E030600, 0x0D000C04, 0x04040207, + 0x0A050A0B, 0x0B060E05, 0x01080102, 0x0D010908, 0x0E01060B, 0x04060200, 0x040A0909, 0x0D01020F, + 0x0302030F, 0x090C0C05, 0x0500040B, 0x0C000708, 0x070E0301, 0x04060C0F, 0x030B0F0E, 0x00010102, + 0x06020F03, 0x040E0F07, 0x0C0E0107, 0x0304000D, 0x0E090E0E, 0x0F0E0301, 0x0F07050C, 0x000D0A07, + 0x00060002, 0x05060A0B, 0x050A0605, 0x090C030E, 0x0D08060B, 0x0E0A0202, 0x0707080B, 0x04000203, + 0x07090808, 0x0D0C0E04, 0x03040A0F, 0x03050B0A, 0x0F0C0A03, 0x090E0600, 0x0E080809, 0x0F0D0909, + 0x0000070D, 0x0F080901, 0x0C0A0F04, 0x0E00010A, 0x0A0C0303, 0x00060D01, 0x03010704, 0x03050602, + 0x0A040105, 0x0F000B0E, 0x08040201, 0x0E0D0508, 0x0B060806, 0x0F030408, 0x07060302, 0x0D030A01, + 0x0C0B0D06, 0x0407080D, 0x08010203, 0x04060105, 0x00070009, 0x0D0A0C09, 0x02050A0A, 0x0D070308, + 0x02020E0F, 0x0B090D09, 0x05020703, 0x0C020D04, 0x03000501, 0x0F060C0D, 0x00000D01, 0x0F0B0205, + 0x04000506, 0x0E09030B, 0x00000103, 0x0F0C090B, 0x040C080F, 0x010F0C07, 0x000B0700, 0x0F0C0F04, + 0x0401090F, 0x080E0E0A, 0x050A090E, 0x0009080C, 0x080E0C06, 0x0D0C030D, 0x090D0C0D, 0x090D0C0D +}; + +#if defined(__AVX2__) + +#ifdef __GNUC__ +#if __GNUC__ < 8 +#define _mm256_set_m128i(xmm1, xmm2) _mm256_permute2f128_si256(_mm256_castsi128_si256(xmm1), _mm256_castsi128_si256(xmm2), 2) +#define _mm256_set_m128f(xmm1, xmm2) _mm256_permute2f128_ps(_mm256_castps128_ps256(xmm1), _mm256_castps128_ps256(xmm2), 2) +#endif +#endif + +#define ALIGNMENT 32 + +const __m256i vec_3 = _mm256_set1_epi8(3); + +inline __m256i genMask(int i) { + __m256i temp = _mm256_setzero_si256(); // Initialize mask with all zeros + + __m128i lower_part = _mm_set1_epi64x(0); + __m128i upper_part = _mm_set1_epi64x(0); + + if (i > 24) { + lower_part = _mm_set1_epi64x(-1ULL); + upper_part = _mm_set_epi64x(-1ULL >> (32-i)*8,-1ULL); + } else if (i > 16) { + lower_part = _mm_set_epi64x(-1ULL,-1ULL); + upper_part = _mm_set_epi64x(0,-1ULL >> (24-i)*8); + } else if (i > 8) { + lower_part = _mm_set_epi64x(-1ULL >> (16-i)*8,-1ULL); + } else if (i > 0) { + lower_part = _mm_set_epi64x(0,-1ULL >> (8-i)*8); + } + + temp = _mm256_insertf128_si256(temp, lower_part, 0); // Set lower 128 bits + temp = _mm256_insertf128_si256(temp, upper_part, 1); // Set upper 128 bits + return temp; +} + +inline __m128i mullo_epi8(__m128i a, __m128i b) +{ + // unpack and multiply + __m128i dst_even = _mm_mullo_epi16(a, b); + __m128i dst_odd = _mm_mullo_epi16(_mm_srli_epi16(a, 8),_mm_srli_epi16(b, 8)); + // repack +#if defined(__AVX2__) + // only faster if have access to VPBROADCASTW + return _mm_or_si128(_mm_slli_epi16(dst_odd, 8), _mm_and_si128(dst_even, _mm_set1_epi16(0xFF))); +#else + return _mm_or_si128(_mm_slli_epi16(dst_odd, 8), _mm_srli_epi16(_mm_slli_epi16(dst_even,8), 8)); +#endif +} + +inline __m256i _mm256_mul_epi8(__m256i x, __m256i y) { + // Unpack and isolate 2 8 bit numbers from a 16 bit block in each vector using masks + __m256i mask1 = _mm256_set1_epi16(0xFF00); + __m256i mask2 = _mm256_set1_epi16(0x00FF); + + // Store the first and second members of the 8bit multiplication equation in their own 16 bit numbers, shifting down as necessary before calculating + __m256i aa = _mm256_srli_epi16(_mm256_and_si256(x, mask1), 8); + __m256i ab = _mm256_srli_epi16(_mm256_and_si256(y, mask1), 8); + __m256i ba = _mm256_and_si256(x, mask2); + __m256i bb = _mm256_and_si256(y, mask2); + + // Perform the multiplication, and undo any downshifting + __m256i pa = _mm256_slli_epi16(_mm256_mullo_epi16(aa, ab), 8); + __m256i pb = _mm256_mullo_epi16(ba, bb); + + // Mask out unwanted data to maintain isolation + pa = _mm256_and_si256(pa, mask1); + pb = _mm256_and_si256(pb, mask2); + + __m256i result = _mm256_or_si256(pa,pb); + + return result; +} + +inline __m256i _mm256_sllv_epi8(__m256i a, __m256i count) { + __m256i mask_hi = _mm256_set1_epi32(0xFF00FF00); + __m256i multiplier_lut = _mm256_set_epi8(0,0,0,0, 0,0,0,0, 0x80,0x40,0x20,0x10, 0x08,0x04,0x02,0x01, 0,0,0,0, 0,0,0,0, 0x80,0x40,0x20,0x10, 0x08,0x04,0x02,0x01); + + __m256i count_sat = _mm256_min_epu8(count, _mm256_set1_epi8(8)); /* AVX shift counts are not masked. So a_i << n_i = 0 for n_i >= 8. count_sat is always less than 9.*/ + __m256i multiplier = _mm256_shuffle_epi8(multiplier_lut, count_sat); /* Select the right multiplication factor in the lookup table. */ + + __m256i x_lo = _mm256_mullo_epi16(a, multiplier); /* Unfortunately _mm256_mullo_epi8 doesn't exist. Split the 16 bit elements in a high and low part. */ + + __m256i multiplier_hi = _mm256_srli_epi16(multiplier, 8); /* The multiplier of the high bits. */ + __m256i a_hi = _mm256_and_si256(a, mask_hi); /* Mask off the low bits. */ + __m256i x_hi = _mm256_mullo_epi16(a_hi, multiplier_hi); + __m256i x = _mm256_blendv_epi8(x_lo, x_hi, mask_hi); /* Merge the high and low part. */ + + return x; +} + + +inline __m256i _mm256_srlv_epi8(__m256i a, __m256i count) { + __m256i mask_hi = _mm256_set1_epi32(0xFF00FF00); + __m256i multiplier_lut = _mm256_set_epi8(0,0,0,0, 0,0,0,0, 0x01,0x02,0x04,0x08, 0x10,0x20,0x40,0x80, 0,0,0,0, 0,0,0,0, 0x01,0x02,0x04,0x08, 0x10,0x20,0x40,0x80); + + __m256i count_sat = _mm256_min_epu8(count, _mm256_set1_epi8(8)); /* AVX shift counts are not masked. So a_i >> n_i = 0 for n_i >= 8. count_sat is always less than 9.*/ + __m256i multiplier = _mm256_shuffle_epi8(multiplier_lut, count_sat); /* Select the right multiplication factor in the lookup table. */ + __m256i a_lo = _mm256_andnot_si256(mask_hi, a); /* Mask off the high bits. */ + __m256i multiplier_lo = _mm256_andnot_si256(mask_hi, multiplier); /* The multiplier of the low bits. */ + __m256i x_lo = _mm256_mullo_epi16(a_lo, multiplier_lo); /* Shift left a_lo by multiplying. */ + x_lo = _mm256_srli_epi16(x_lo, 7); /* Shift right by 7 to get the low bits at the right position. */ + + __m256i multiplier_hi = _mm256_and_si256(mask_hi, multiplier); /* The multiplier of the high bits. */ + __m256i x_hi = _mm256_mulhi_epu16(a, multiplier_hi); /* Variable shift left a_hi by multiplying. Use a instead of a_hi because the a_lo bits don't interfere */ + x_hi = _mm256_slli_epi16(x_hi, 1); /* Shift left by 1 to get the high bits at the right position. */ + __m256i x = _mm256_blendv_epi8(x_lo, x_hi, mask_hi); /* Merge the high and low part. */ + + return x; +} + +inline __m256i _mm256_rolv_epi8(__m256i x, __m256i y) { + // Ensure the shift counts are within the range of 0 to 7 + __m256i y_mod = _mm256_and_si256(y, _mm256_set1_epi8(7)); + + // Left shift x by y_mod + __m256i left_shift = _mm256_sllv_epi8(x, y_mod); + + // Compute the right shift counts + __m256i right_shift_counts = _mm256_sub_epi8(_mm256_set1_epi8(8), y_mod); + + // Right shift x by (8 - y_mod) + __m256i right_shift = _mm256_srlv_epi8(x, right_shift_counts); + + // Combine the left-shifted and right-shifted results using bitwise OR + __m256i rotated = _mm256_or_si256(left_shift, right_shift); + + return rotated; +} + +// Rotates x left by r bits +inline __m256i _mm256_rol_epi8(__m256i x, int r) { + // Unpack 2 8 bit numbers into their own vectors, and isolate them using masks + __m256i mask1 = _mm256_set1_epi16(0x00FF); + __m256i mask2 = _mm256_set1_epi16(0xFF00); + __m256i a = _mm256_and_si256(x, mask1); + __m256i b = _mm256_and_si256(x, mask2); + + // Apply the 8bit rotation to the lower 8 bits, then mask out any extra/overflow + __m256i shiftedA = _mm256_slli_epi16(a, r); + __m256i wrappedA = _mm256_srli_epi16(a, 8 - r); + __m256i rotatedA = _mm256_or_si256(shiftedA, wrappedA); + rotatedA = _mm256_and_si256(rotatedA, mask1); + + // Apply the 8bit rotation to the upper 8 bits, then mask out any extra/overflow + __m256i shiftedB = _mm256_slli_epi16(b, r); + __m256i wrappedB = _mm256_srli_epi16(b, 8 - r); + __m256i rotatedB = _mm256_or_si256(shiftedB, wrappedB); + rotatedB = _mm256_and_si256(rotatedB, mask2); + + // Re-pack the isolated results into a 16-bit block + __m256i rotated = _mm256_or_si256(rotatedA, rotatedB); + + return rotated; +} + +// parallelPopcnt16bytes- find population count for 8-bit groups in xmm (16 groups) +// each unsigned char of xmm result contains a value ranging from 0 to 8 +// +inline __m128i parallelPopcnt16bytes(__m128i xmm) +{ + const __m128i mask4 = _mm_set1_epi8 (0x0F); + const __m128i lookup = _mm_setr_epi8 (0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4); + __m128i low, high, count; + + low = _mm_and_si128 (mask4, xmm); + high = _mm_and_si128 (mask4, _mm_srli_epi16 (xmm, 4)); + count = _mm_add_epi8 (_mm_shuffle_epi8 (lookup, low), _mm_shuffle_epi8 (lookup, high)); + return count; +} + +inline __m256i popcnt256_epi8(__m256i data) { + __m128i hi = _mm256_extractf128_si256(data, 1); + __m128i lo = _mm256_castsi256_si128(data); + + hi = parallelPopcnt16bytes(hi); + lo = parallelPopcnt16bytes(lo); + + __m256i pop = _mm256_set_m128i(hi,lo); + return pop; +} + +inline int check_results(__m256i avx_result, unsigned char* scalar_result, int num_elements) { + union { + __m256i avx; + unsigned char scalar[32]; + } converter; + + converter.avx = avx_result; + + for(int i = 0; i < num_elements; ++i) { + if (converter.scalar[i] != scalar_result[i]) { + std::cout << "Mismatch at index: " << i << std::endl; + std::cout << "AVX: " << static_cast(converter.scalar[i]) + << " Scalar: " << static_cast(scalar_result[i]) << std::endl; + return 0; + } + } + + return 1; +} + +inline __m256i _mm256_reverse_epi8(__m256i input) { + const __m256i mask_0f = _mm256_set1_epi8(0x0F); + const __m256i mask_33 = _mm256_set1_epi8(0x33); + const __m256i mask_55 = _mm256_set1_epi8(0x55); + + // b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; + __m256i temp = _mm256_and_si256(input, mask_0f); + temp = _mm256_slli_epi16(temp, 4); + input = _mm256_and_si256(input, _mm256_andnot_si256(mask_0f, _mm256_set1_epi8(0xFF))); + input = _mm256_srli_epi16(input, 4); + input = _mm256_or_si256(input, temp); + + // b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + temp = _mm256_and_si256(input, mask_33); + temp = _mm256_slli_epi16(temp, 2); + input = _mm256_and_si256(input, _mm256_andnot_si256(mask_33, _mm256_set1_epi8(0xFF))); + input = _mm256_srli_epi16(input, 2); + input = _mm256_or_si256(input, temp); + + // b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + temp = _mm256_and_si256(input, mask_55); + temp = _mm256_slli_epi16(temp, 1); + input = _mm256_and_si256(input, _mm256_andnot_si256(mask_55, _mm256_set1_epi8(0xFF))); + input = _mm256_srli_epi16(input, 1); + input = _mm256_or_si256(input, temp); + + return input; +} + +uint32_t branchComputeCPU_avx2(RC4_KEY key, unsigned char *sData); +#else +#define ALIGNMENT 16 +#endif + +#define rl8(x, y) ((x << (y%8) | x >> (8-(y%8)))) + +inline unsigned char +leftRotate8(unsigned char n, unsigned d) +{ // rotate n by d bits +#if defined(_WIN32) + return _rotl8(n, d); +#else + d = d % 8; + return (n << d) | (n >> (8 - d)); +#endif +} + +inline unsigned char reverse8(unsigned char b) +{ + return (b * 0x0202020202ULL & 0x010884422010ULL) % 1023; +} + +template +inline void prefetch(T *data, int size, int hint) { + const size_t prefetch_distance = 256; // Prefetch 8 cache lines ahead + const size_t cache_line_size = 64; // Assuming a 64-byte cache line + + //for (size_t i = 0; i < size; i += prefetch_distance * cache_line_size) { + // __builtin_prefetch(&data[i], 0, hint); + //} + switch(hint) { + case 0: + for (size_t i = 0; i < size; i += prefetch_distance * cache_line_size) { + __builtin_prefetch(&data[i], 0, 0); + } + break; + case 1: + for (size_t i = 0; i < size; i += prefetch_distance * cache_line_size) { + __builtin_prefetch(&data[i], 0, 1); + } + break; + case 2: + for (size_t i = 0; i < size; i += prefetch_distance * cache_line_size) { + __builtin_prefetch(&data[i], 0, 2); + } + break; + case 3: + for (size_t i = 0; i < size; i += prefetch_distance * cache_line_size) { + __builtin_prefetch(&data[i], 0, 3); + } + break; + default: + break; + } +} + +template +inline void insertElement(T* arr, int& size, int capacity, int index, const T& element) { + if (size < capacity) { + // Shift elements to the right + for (int i = size - 1; i >= index; i--) { + arr[i + 1] = arr[i]; + } + + // Insert the new element + arr[index] = element; + + // Increase the size + size++; + } else { + std::cout << "Array is full. Cannot insert element." << std::endl; + } +} + +void AstroBWTv3(const unsigned char *input, int inputLen, unsigned char *outputhash); +uint32_t branchComputeCPU(RC4_KEY key, unsigned char *sData); +uint32_t wolfCompute(RC4_KEY key, unsigned char *sData); + +#if defined(__aarch64__) +uint32_t branchComputeCPU_aarch64(RC4_KEY key, unsigned char *sData) +#endif + +#endif \ No newline at end of file diff --git a/src/Native/libmeraki/dllmain.cpp b/src/Native/libdero/dllmain.cpp similarity index 100% rename from src/Native/libmeraki/dllmain.cpp rename to src/Native/libdero/dllmain.cpp diff --git a/src/Native/libmeraki/exports.cpp b/src/Native/libdero/exports.cpp similarity index 80% rename from src/Native/libmeraki/exports.cpp rename to src/Native/libdero/exports.cpp index 2004b4f482..7e5b64fe8b 100644 --- a/src/Native/libmeraki/exports.cpp +++ b/src/Native/libdero/exports.cpp @@ -14,3 +14,16 @@ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMA 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. */ + +#include "astrobwtv3.h" + +#ifdef _WIN32 +#define MODULE_API __declspec(dllexport) +#else +#define MODULE_API +#endif + +extern "C" MODULE_API void astroBWTv3_export(const unsigned char* input, int inputLen, unsigned char* output) +{ + AstroBWTv3(input, inputLen, output); +} \ No newline at end of file diff --git a/src/Native/libdero/include/Salsa20.h b/src/Native/libdero/include/Salsa20.h new file mode 100644 index 0000000000..97dfe37e06 --- /dev/null +++ b/src/Native/libdero/include/Salsa20.h @@ -0,0 +1,116 @@ +// Copyright (c) 2015 Nezametdinov E. Ildus +// See LICENSE.TXT for licensing details + +#ifndef SALSA20_H +#define SALSA20_H + +#include +#include +#include +#include + +namespace ucstk +{ + + using std::size_t; + using std::int32_t; + using std::uint8_t; + using std::uint32_t; + + /** + * Represents Salsa20 cypher. Supports only 256-bit keys. + */ + class Salsa20 + { + public: + /// Helper constants + enum: size_t + { + VECTOR_SIZE = 16, + BLOCK_SIZE = 64, + KEY_SIZE = 32, + IV_SIZE = 8 + }; + + /** + * \brief Constructs cypher with given key. + * \param[in] key 256-bit key + */ + inline Salsa20(const uint8_t* key = nullptr); + Salsa20(const Salsa20&) = default; + Salsa20(Salsa20&&) = default; + ~Salsa20() = default; + Salsa20& operator =(const Salsa20&) = default; + Salsa20& operator =(Salsa20&&) = default; + + /** + * \brief Sets key. + * \param[in] key 256-bit key + */ + inline void setKey(const uint8_t* key); + + /** + * \brief Sets IV. + * \param[in] iv 64-bit IV + */ + inline void setIv(const uint8_t* iv); + + /** + * \brief Generates key stream. + * \param[out] output generated key stream + */ + inline void generateKeyStream(uint8_t output[BLOCK_SIZE]); + + /** + * \brief Processes blocks. + * \param[in] input input + * \param[out] output output + * \param[in] numBlocks number of blocks + */ + inline void processBlocks(const uint8_t* input, uint8_t* output, size_t numBlocks); + + /** + * \brief Processes bytes. + * + * This function should be used carefully. If number of bytes is not multiple of + * block size, then next call to the processBlocks function will be invalid. + * Normally this function should be used once at the end of encryption or + * decryption. + * \param[in] input input + * \param[out] output output + * \param[in] numBytes number of bytes + */ + inline void processBytes(const uint8_t* input, uint8_t* output, size_t numBytes); + + private: + /** + * \brief Rotates value. + * \param[in] value value + * \param[in] numBits number of bits to rotate + * \return result of the rotation + */ + inline uint32_t rotate(uint32_t value, uint32_t numBits); + + /** + * \brief Converts 32-bit unsigned integer value to the array of bytes. + * \param[in] value 32-bit unsigned integer value + * \param[out] array array of bytes + */ + inline void convert(uint32_t value, uint8_t* array); + + /** + * \brief Converts array of bytes to the 32-bit unsigned integer value. + * \param[in] array array of bytes + * \return 32-bit unsigned integer value + */ + inline uint32_t convert(const uint8_t* array); + + // Data members + uint32_t vector_[VECTOR_SIZE]; + + }; + +} + +#include "Salsa20.inl" +#endif \ No newline at end of file diff --git a/src/Native/libdero/include/Salsa20.inl b/src/Native/libdero/include/Salsa20.inl new file mode 100644 index 0000000000..e974ff767e --- /dev/null +++ b/src/Native/libdero/include/Salsa20.inl @@ -0,0 +1,161 @@ +// Copyright (c) 2015 Nezametdinov E. Ildus +// See LICENSE.TXT for licensing details + +#include "Salsa20.h" + +namespace ucstk +{ + + Salsa20::Salsa20(const uint8_t* key) + { + std::memset(vector_, 0, sizeof(vector_)); + setKey(key); + } + + //---------------------------------------------------------------------------------- + void Salsa20::setKey(const uint8_t* key) + { + static const char constants[] = "expand 32-byte k"; + + if(key == nullptr) + return; + + vector_[0] = convert(reinterpret_cast(&constants[0])); + vector_[1] = convert(&key[0]); + vector_[2] = convert(&key[4]); + vector_[3] = convert(&key[8]); + vector_[4] = convert(&key[12]); + vector_[5] = convert(reinterpret_cast(&constants[4])); + + std::memset(&vector_[6], 0, 4 * sizeof(uint32_t)); + + vector_[10] = convert(reinterpret_cast(&constants[8])); + vector_[11] = convert(&key[16]); + vector_[12] = convert(&key[20]); + vector_[13] = convert(&key[24]); + vector_[14] = convert(&key[28]); + vector_[15] = convert(reinterpret_cast(&constants[12])); + } + + //---------------------------------------------------------------------------------- + void Salsa20::setIv(const uint8_t* iv) + { + if(iv == nullptr) + return; + + vector_[6] = convert(&iv[0]); + vector_[7] = convert(&iv[4]); + vector_[8] = vector_[9] = 0; + } + + //---------------------------------------------------------------------------------- + void Salsa20::generateKeyStream(uint8_t output[BLOCK_SIZE]) + { + uint32_t x[VECTOR_SIZE]; + std::memcpy(x, vector_, sizeof(vector_)); + + for(int32_t i = 20; i > 0; i -= 2) + { + x[4 ] ^= rotate(static_cast(x[0 ] + x[12]), 7); + x[8 ] ^= rotate(static_cast(x[4 ] + x[0 ]), 9); + x[12] ^= rotate(static_cast(x[8 ] + x[4 ]), 13); + x[0 ] ^= rotate(static_cast(x[12] + x[8 ]), 18); + x[9 ] ^= rotate(static_cast(x[5 ] + x[1 ]), 7); + x[13] ^= rotate(static_cast(x[9 ] + x[5 ]), 9); + x[1 ] ^= rotate(static_cast(x[13] + x[9 ]), 13); + x[5 ] ^= rotate(static_cast(x[1 ] + x[13]), 18); + x[14] ^= rotate(static_cast(x[10] + x[6 ]), 7); + x[2 ] ^= rotate(static_cast(x[14] + x[10]), 9); + x[6 ] ^= rotate(static_cast(x[2 ] + x[14]), 13); + x[10] ^= rotate(static_cast(x[6 ] + x[2 ]), 18); + x[3 ] ^= rotate(static_cast(x[15] + x[11]), 7); + x[7 ] ^= rotate(static_cast(x[3 ] + x[15]), 9); + x[11] ^= rotate(static_cast(x[7 ] + x[3 ]), 13); + x[15] ^= rotate(static_cast(x[11] + x[7 ]), 18); + x[1 ] ^= rotate(static_cast(x[0 ] + x[3 ]), 7); + x[2 ] ^= rotate(static_cast(x[1 ] + x[0 ]), 9); + x[3 ] ^= rotate(static_cast(x[2 ] + x[1 ]), 13); + x[0 ] ^= rotate(static_cast(x[3 ] + x[2 ]), 18); + x[6 ] ^= rotate(static_cast(x[5 ] + x[4 ]), 7); + x[7 ] ^= rotate(static_cast(x[6 ] + x[5 ]), 9); + x[4 ] ^= rotate(static_cast(x[7 ] + x[6 ]), 13); + x[5 ] ^= rotate(static_cast(x[4 ] + x[7 ]), 18); + x[11] ^= rotate(static_cast(x[10] + x[9 ]), 7); + x[8 ] ^= rotate(static_cast(x[11] + x[10]), 9); + x[9 ] ^= rotate(static_cast(x[8 ] + x[11]), 13); + x[10] ^= rotate(static_cast(x[9 ] + x[8 ]), 18); + x[12] ^= rotate(static_cast(x[15] + x[14]), 7); + x[13] ^= rotate(static_cast(x[12] + x[15]), 9); + x[14] ^= rotate(static_cast(x[13] + x[12]), 13); + x[15] ^= rotate(static_cast(x[14] + x[13]), 18); + } + + for(size_t i = 0; i < VECTOR_SIZE; ++i) + { + x[i] += vector_[i]; + convert(x[i], &output[4 * i]); + } + + ++vector_[8]; + vector_[9] += vector_[8] == 0 ? 1 : 0; + } + + //---------------------------------------------------------------------------------- + void Salsa20::processBlocks(const uint8_t* input, uint8_t* output, size_t numBlocks) + { + assert(input != nullptr && output != nullptr); + + uint8_t keyStream[BLOCK_SIZE]; + + for(size_t i = 0; i < numBlocks; ++i) + { + generateKeyStream(keyStream); + + for(size_t j = 0; j < BLOCK_SIZE; ++j) + *(output++) = keyStream[j] ^ *(input++); + } + } + + //---------------------------------------------------------------------------------- + void Salsa20::processBytes(const uint8_t* input, uint8_t* output, size_t numBytes) + { + assert(input != nullptr && output != nullptr); + + uint8_t keyStream[BLOCK_SIZE]; + size_t numBytesToProcess; + + while(numBytes != 0) + { + generateKeyStream(keyStream); + numBytesToProcess = numBytes >= BLOCK_SIZE ? BLOCK_SIZE : numBytes; + + for(size_t i = 0; i < numBytesToProcess; ++i, --numBytes) + *(output++) = keyStream[i] ^ *(input++); + } + } + + //---------------------------------------------------------------------------------- + uint32_t Salsa20::rotate(uint32_t value, uint32_t numBits) + { + return (value << numBits) | (value >> (32 - numBits)); + } + + //---------------------------------------------------------------------------------- + void Salsa20::convert(uint32_t value, uint8_t* array) + { + array[0] = static_cast(value >> 0); + array[1] = static_cast(value >> 8); + array[2] = static_cast(value >> 16); + array[3] = static_cast(value >> 24); + } + + //---------------------------------------------------------------------------------- + uint32_t Salsa20::convert(const uint8_t* array) + { + return ((static_cast(array[0]) << 0) | + (static_cast(array[1]) << 8) | + (static_cast(array[2]) << 16) | + (static_cast(array[3]) << 24)); + } + +} \ No newline at end of file diff --git a/src/Native/libdero/include/endian.hpp b/src/Native/libdero/include/endian.hpp new file mode 100644 index 0000000000..1b5f12ee67 --- /dev/null +++ b/src/Native/libdero/include/endian.hpp @@ -0,0 +1,14 @@ +#ifndef ENDIAN +#define ENDIAN + +inline bool littleEndian() +{ + int n = 1; + // little endian if true + if(*(char *)&n == 1) { + return true; + } + return false; +} + +#endif \ No newline at end of file diff --git a/src/Native/libdero/include/fnv1a.h b/src/Native/libdero/include/fnv1a.h new file mode 100644 index 0000000000..54fb75ddae --- /dev/null +++ b/src/Native/libdero/include/fnv1a.h @@ -0,0 +1,54 @@ +#pragma once +#include + +//fnv1a 32 and 64 bit hash functions +// key is the data to hash, len is the size of the data (or how much of it to hash against) +// code license: public domain or equivalent +// post: https://notes.underscorediscovery.com/constexpr-fnv1a/ + +inline uint32_t hash_32_fnv1a(const void* key, const uint32_t len) { + + const char* data = (char*)key; + uint32_t hash = 0x811c9dc5; + uint32_t prime = 0x1000193; + + for(int i = 0; i < len; ++i) { + uint8_t value = data[i]; + hash = hash ^ value; + hash *= prime; + } + + return hash; + +} //hash_32_fnv1a + +inline uint64_t hash_64_fnv1a_256(const void* key) { + const char* data = (char*)key; + uint64_t hash = 0xcbf29ce484222325; + uint64_t prime = 0x100000001b3; + +#pragma GCC unroll 256 + for(int i = 0; i < 256; ++i) { + uint8_t value = data[i]; + hash = hash ^ value; + hash *= prime; + } + + return hash; + +} + +inline uint64_t hash_64_fnv1a(const void* key, const uint64_t len) { + const char* data = (char*)key; + uint64_t hash = 0xcbf29ce484222325; + uint64_t prime = 0x100000001b3; + + for(int i = 0; i < len; ++i) { + uint8_t value = data[i]; + hash = hash ^ value; + hash *= prime; + } + + return hash; + +} //hash_64_fnv1a \ No newline at end of file diff --git a/src/Native/libdero/include/highwayhash/arch_specific.cc b/src/Native/libdero/include/highwayhash/arch_specific.cc new file mode 100644 index 0000000000..2105dd98fc --- /dev/null +++ b/src/Native/libdero/include/highwayhash/arch_specific.cc @@ -0,0 +1,193 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 "arch_specific.h" + +#include + +#if HH_ARCH_X64 && !HH_MSC_VERSION +#include +#endif + +#if HH_ARCH_PPC +#if __GLIBC__ +#include // __ppc_get_timebase_freq +#elif __FreeBSD__ +// clang-format off +#include +#include /* must come after sys/types.h */ +// clang-format on +#endif +#endif + +#include // memcpy +#include + +namespace highwayhash { + +const char* TargetName(const TargetBits target_bit) { + switch (target_bit) { + case HH_TARGET_Portable: + return "Portable"; + case HH_TARGET_SSE41: + return "SSE41"; + case HH_TARGET_AVX2: + return "AVX2"; + case HH_TARGET_VSX: + return "VSX"; + case HH_TARGET_NEON: + return "NEON"; + default: + return nullptr; // zero, multiple, or unknown bits + } +} + +#if HH_ARCH_X64 + +namespace { + +std::string BrandString() { + char brand_string[49]; + uint32_t abcd[4]; + + // Check if brand string is supported (it is on all reasonable Intel/AMD) + Cpuid(0x80000000U, 0, abcd); + if (abcd[0] < 0x80000004U) { + return std::string(); + } + + for (int i = 0; i < 3; ++i) { + Cpuid(0x80000002U + i, 0, abcd); + memcpy(brand_string + i * 16, &abcd, sizeof(abcd)); + } + brand_string[48] = 0; + return brand_string; +} + +} // namespace + +void Cpuid(const uint32_t level, const uint32_t count, + uint32_t* HH_RESTRICT abcd) { +#if HH_MSC_VERSION + int regs[4]; + __cpuidex(regs, level, count); + for (int i = 0; i < 4; ++i) { + abcd[i] = regs[i]; + } +#else + uint32_t a, b, c, d; + __cpuid_count(level, count, a, b, c, d); + abcd[0] = a; + abcd[1] = b; + abcd[2] = c; + abcd[3] = d; +#endif +} + +uint32_t ApicId() { + uint32_t abcd[4]; + Cpuid(1, 0, abcd); + return abcd[1] >> 24; // ebx +} + +#endif // HH_ARCH_X64 + +namespace { + +double DetectNominalClockRate() { +#if HH_ARCH_X64 + const std::string& brand_string = BrandString(); + // Brand strings include the maximum configured frequency. These prefixes are + // defined by Intel CPUID documentation. + const char* prefixes[3] = {"MHz", "GHz", "THz"}; + const double multipliers[3] = {1E6, 1E9, 1E12}; + for (size_t i = 0; i < 3; ++i) { + const size_t pos_prefix = brand_string.find(prefixes[i]); + if (pos_prefix != std::string::npos) { + const size_t pos_space = brand_string.rfind(' ', pos_prefix - 1); + if (pos_space != std::string::npos) { + const std::string digits = + brand_string.substr(pos_space + 1, pos_prefix - pos_space - 1); + return std::stod(digits) * multipliers[i]; + } + } + } +#elif HH_ARCH_PPC + double freq = -1; +#if __linux__ + char line[200]; + char* s; + char* value; + + FILE* f = fopen("/proc/cpuinfo", "r"); + if (f != nullptr) { + while (fgets(line, sizeof(line), f) != nullptr) { + // NOTE: the ':' is the only character we can rely on + if (!(value = strchr(line, ':'))) continue; + // terminate the valuename + *value++ = '\0'; + // skip any leading spaces + while (*value == ' ') value++; + if ((s = strchr(value, '\n'))) *s = '\0'; + + if (!strncasecmp(line, "clock", strlen("clock")) && + sscanf(value, "%lf", &freq) == 1) { + freq *= 1E6; + break; + } + } + fclose(f); + return freq; + } +#elif __FreeBSD__ + size_t length = sizeof(freq); + sysctlbyname("dev.cpu.0.freq", &freq, &length, NULL, 0); + freq *= 1E6; + return freq; +#endif +#endif + + return 0.0; +} + +} // namespace + +double NominalClockRate() { + // Thread-safe caching - this is called several times. + static const double cycles_per_second = DetectNominalClockRate(); + return cycles_per_second; +} + +double InvariantTicksPerSecond() { +#if HH_ARCH_PPC +#if __GLIBC__ + static const double cycles_per_second = __ppc_get_timebase_freq(); +#elif __FreeBSD__ + double cycles_per_second = 0; + size_t length = sizeof(cycles_per_second); + sysctlbyname("kern.timecounter.tc.timebase.frequency", &cycles_per_second, + &length, NULL, 0); +#elif __OpenBSD__ + /* There is currently no method of retrieving this via userland. + * This value is correct for Power8 and Power9. + */ + static const double cycles_per_second = 512000000; +#endif + return cycles_per_second; +#else + return NominalClockRate(); +#endif +} + +} // namespace highwayhash diff --git a/src/Native/libdero/include/highwayhash/arch_specific.h b/src/Native/libdero/include/highwayhash/arch_specific.h new file mode 100644 index 0000000000..09f1bef4b4 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/arch_specific.h @@ -0,0 +1,179 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_ARCH_SPECIFIC_H_ +#define HIGHWAYHASH_ARCH_SPECIFIC_H_ + +// WARNING: this is a "restricted" header because it is included from +// translation units compiled with different flags. This header and its +// dependencies must not define any function unless it is static inline and/or +// within namespace HH_TARGET_NAME. +// +// Background: older GCC/Clang require flags such as -mavx2 before AVX2 SIMD +// intrinsics can be used. These intrinsics are only used within blocks that +// first verify CPU capabilities. However, the flag also allows the compiler to +// generate AVX2 code in other places. This can violate the One Definition Rule, +// which requires multiple instances of a function with external linkage +// (e.g. extern inline in a header) to be "equivalent". To prevent the resulting +// crashes on non-AVX2 CPUs, any header (transitively) included from a +// translation unit compiled with different flags is "restricted". This means +// all function definitions must have internal linkage (e.g. static inline), or +// reside in namespace HH_TARGET_NAME, which expands to a name unique to the +// current compiler flags. +// +// Most C system headers are safe to include, but C++ headers should generally +// be avoided because they often do not specify static linkage and cannot +// reliably be wrapped in a namespace. + +#include "compiler_specific.h" + +#include + +#if HH_MSC_VERSION +#include // _byteswap_* +#endif + +namespace highwayhash { + +#if defined(__x86_64__) || defined(_M_X64) +#define HH_ARCH_X64 1 +#else +#define HH_ARCH_X64 0 +#endif + +#if defined(__aarch64__) || defined(__arm64__) +#define HH_ARCH_AARCH64 1 +#else +#define HH_ARCH_AARCH64 0 +#endif + +#ifdef __arm__ +#define HH_ARCH_ARM 1 +#else +#define HH_ARCH_ARM 0 +#endif + +#if defined(__ARM_NEON__) || defined(__ARM_NEON) +#define HH_ARCH_NEON 1 +#else +#define HH_ARCH_NEON 0 +#endif + +#if defined(__powerpc64__) || defined(_M_PPC) +#define HH_ARCH_PPC 1 +#else +#define HH_ARCH_PPC 0 +#endif + +// Target := instruction set extension(s) such as SSE41. A translation unit can +// only provide a single target-specific implementation because they require +// different compiler flags. + +// Either the build system specifies the target by defining HH_TARGET_NAME +// (which is necessary for Portable on X64, and SSE41 on MSVC), or we'll choose +// the most efficient one that can be compiled given the current flags: +#ifndef HH_TARGET_NAME + +// To avoid excessive code size and dispatch overhead, we only support a few +// groups of extensions, e.g. FMA+BMI2+AVX+AVX2 =: "AVX2". These names must +// match the HH_TARGET_* suffixes below. +#ifdef __AVX2__ +#define HH_TARGET_NAME AVX2 +// MSVC does not set SSE4_1, but it does set AVX; checking for the latter means +// we at least get SSE4 on machines supporting AVX but not AVX2. +// https://stackoverflow.com/questions/18563978/detect-the-availability-of-sse-sse2-instruction-set-in-visual-studio +#elif defined(__SSE4_1__) || (HH_MSC_VERSION != 0 && defined(__AVX__)) +#define HH_TARGET_NAME SSE41 +#elif defined(__VSX__) +#define HH_TARGET_NAME VSX +#elif HH_ARCH_NEON +#define HH_TARGET_NAME NEON +#else +#define HH_TARGET_NAME Portable +#endif + +#endif // HH_TARGET_NAME + +#define HH_CONCAT(first, second) first##second +// Required due to macro expansion rules. +#define HH_EXPAND_CONCAT(first, second) HH_CONCAT(first, second) +// Appends HH_TARGET_NAME to "identifier_prefix". +#define HH_ADD_TARGET_SUFFIX(identifier_prefix) \ + HH_EXPAND_CONCAT(identifier_prefix, HH_TARGET_NAME) + +// HH_TARGET expands to an integer constant. Typical usage: HHStateT. +// This ensures your code will work correctly when compiler flags are changed, +// and benefit from subsequently added targets/specializations. +#define HH_TARGET HH_ADD_TARGET_SUFFIX(HH_TARGET_) + +// Deprecated former name of HH_TARGET; please use HH_TARGET instead. +#define HH_TARGET_PREFERRED HH_TARGET + +// Associate targets with integer literals so the preprocessor can compare them +// with HH_TARGET. Do not instantiate templates with these values - use +// HH_TARGET instead. Must be unique powers of two, see TargetBits. Always +// defined even if unavailable on this HH_ARCH to allow calling TargetName. +// The suffixes must match the HH_TARGET_NAME identifiers. +#define HH_TARGET_Portable 1 +#define HH_TARGET_SSE41 2 +#define HH_TARGET_AVX2 4 +#define HH_TARGET_VSX 8 +#define HH_TARGET_NEON 16 + +// Bit array for one or more HH_TARGET_*. Used to indicate which target(s) are +// supported or were called by InstructionSets::RunAll. +using TargetBits = unsigned; + +namespace HH_TARGET_NAME { + +// Calls func(bit_value) for every nonzero bit in "bits". +template +void ForeachTarget(TargetBits bits, const Func& func) { + while (bits != 0) { + const TargetBits lowest = bits & (~bits + 1); + func(lowest); + bits &= ~lowest; + } +} + +} // namespace HH_TARGET_NAME + +// Returns a brief human-readable string literal identifying one of the above +// bits, or nullptr if zero, multiple, or unknown bits are set. +const char* TargetName(const TargetBits target_bit); + +// Returns the nominal (without Turbo Boost) CPU clock rate [Hertz]. Useful for +// (roughly) characterizing the CPU speed. +double NominalClockRate(); + +// Returns tsc_timer frequency, useful for converting ticks to seconds. This is +// unaffected by CPU throttling ("invariant"). Thread-safe. Returns timebase +// frequency on PPC and NominalClockRate on all other platforms. +double InvariantTicksPerSecond(); + +#if HH_ARCH_X64 + +// Calls CPUID instruction with eax=level and ecx=count and returns the result +// in abcd array where abcd = {eax, ebx, ecx, edx} (hence the name abcd). +void Cpuid(const uint32_t level, const uint32_t count, + uint32_t* HH_RESTRICT abcd); + +// Returns the APIC ID of the CPU on which we're currently running. +uint32_t ApicId(); + +#endif // HH_ARCH_X64 + +} // namespace highwayhash + +#endif // HIGHWAYHASH_ARCH_SPECIFIC_H_ diff --git a/src/Native/libdero/include/highwayhash/benchmark.cc b/src/Native/libdero/include/highwayhash/benchmark.cc new file mode 100644 index 0000000000..e7bbb28862 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/benchmark.cc @@ -0,0 +1,331 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +// Measures hash function throughput for various input sizes. + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "arch_specific.h" +#include "compiler_specific.h" +#include "instruction_sets.h" +#include "nanobenchmark.h" +#include "robust_statistics.h" + +// Which functions to enable (includes check for compiler support) +#define BENCHMARK_SIP 0 +#define BENCHMARK_SIP_TREE 0 +#define BENCHMARK_HIGHWAY 1 +#define BENCHMARK_HIGHWAY_CAT 1 +#define BENCHMARK_FARM 0 +#define BENCHMARK_INTERNAL 0 + +#include "highwayhash_test_target.h" +#if BENCHMARK_SIP +#include "sip_hash.h" +#endif +#if BENCHMARK_SIP_TREE +#include "scalar_sip_tree_hash.h" +#include "sip_tree_hash.h" +#endif +#if BENCHMARK_FARM +#include "third_party/farmhash/src/farmhash.h" +#endif + +#if BENCHMARK_INTERNAL +// Placeholder for include +#endif + +namespace highwayhash { +namespace { + +// Stores time measurements from benchmarks, with support for printing them +// as LaTeX figures or tables. +class Measurements { + public: + void Add(const char* caption, const size_t bytes, const double cycles) { + const float cpb = static_cast(cycles / bytes); + results_.emplace_back(caption, static_cast(bytes), cpb); + } + + // Prints results as a LaTeX table (only for in_sizes matching the + // desired values). + void PrintTable(const std::vector& in_sizes) { + std::vector unique = in_sizes; + std::sort(unique.begin(), unique.end()); + unique.erase(std::unique(unique.begin(), unique.end()), unique.end()); + + printf("\\begin{tabular}{"); + for (size_t i = 0; i < unique.size() + 1; ++i) { + printf("%s", i == 0 ? "r" : "|r"); + } + printf("}\n\\toprule\nAlgorithm"); + for (const size_t in_size : unique) { + printf(" & %zu", in_size); + } + printf("\\\\\n\\midrule\n"); + + const SpeedsForCaption cpb_for_caption = SortByCaptionFilterBySize(unique); + for (const auto& item : cpb_for_caption) { + printf("%22s", item.first.c_str()); + for (const float cpb : item.second) { + printf(" & %5.2f", cpb); + } + printf("\\\\\n"); + } + } + + // Prints results suitable for pgfplots. + void PrintPlots() { + const SpeedsForCaption cpb_for_caption = SortByCaption(); + assert(!cpb_for_caption.empty()); + const size_t num_sizes = cpb_for_caption.begin()->second.size(); + + printf("Size "); + // Flatten per-caption vectors into one iterator. + std::vector::const_iterator> iterators; + for (const auto& item : cpb_for_caption) { + printf("%21s ", item.first.c_str()); + assert(item.second.size() == num_sizes); + iterators.push_back(item.second.begin()); + } + printf("\n"); + + const std::vector& sizes = UniqueSizes(); + assert(num_sizes == sizes.size()); + for (int i = 0; i < static_cast(num_sizes); ++i) { + printf("%d ", sizes[i]); + for (auto& it : iterators) { + printf("%5.2f ", 1.0f / *it); // bytes per cycle + ++it; + } + printf("\n"); + } + } + + private: + struct Result { + Result(const char* caption, const int in_size, const float cpb) + : caption(caption), in_size(in_size), cpb(cpb) {} + + // Algorithm name. + std::string caption; + // Size of the input data [bytes]. + int in_size; + // Measured throughput [cycles per byte]. + float cpb; + }; + + // Returns set of all input sizes for the first column of a size/speed plot. + std::vector UniqueSizes() { + std::vector sizes; + sizes.reserve(results_.size()); + for (const Result& result : results_) { + sizes.push_back(result.in_size); + } + std::sort(sizes.begin(), sizes.end()); + sizes.erase(std::unique(sizes.begin(), sizes.end()), sizes.end()); + return sizes; + } + + using SpeedsForCaption = std::map>; + + SpeedsForCaption SortByCaption() const { + SpeedsForCaption cpb_for_caption; + for (const Result& result : results_) { + cpb_for_caption[result.caption].push_back(result.cpb); + } + return cpb_for_caption; + } + + // Only includes measurement results matching one of the given sizes. + SpeedsForCaption SortByCaptionFilterBySize( + const std::vector& in_sizes) const { + SpeedsForCaption cpb_for_caption; + for (const Result& result : results_) { + for (const size_t in_size : in_sizes) { + if (result.in_size == static_cast(in_size)) { + cpb_for_caption[result.caption].push_back(result.cpb); + } + } + } + return cpb_for_caption; + } + + std::vector results_; +}; + +void AddMeasurements(DurationsForInputs* input_map, const char* caption, + Measurements* measurements) { + for (size_t i = 0; i < input_map->num_items; ++i) { + const DurationsForInputs::Item& item = input_map->items[i]; + std::vector durations(item.durations, + item.durations + item.num_durations); + const float median_ticks = Median(&durations); + const float variability = MedianAbsoluteDeviation(durations, median_ticks); + const double median_cpu_cycles = + (median_ticks / InvariantTicksPerSecond()) * NominalClockRate(); + printf("%s %4zu: median=%6.1f ticks; median L1 norm =%4.1f ticks\n", + caption, item.input, median_ticks, variability); + measurements->Add(caption, item.input, median_cpu_cycles); + } + input_map->num_items = 0; +} + +#if BENCHMARK_SIP || BENCHMARK_FARM || BENCHMARK_INTERNAL || \ + (BENCHMARK_SIP_TREE && defined(__AVX2__)) + +void MeasureAndAdd(DurationsForInputs* input_map, const char* caption, + const Func func, Measurements* measurements) { + MeasureDurations(func, input_map); + AddMeasurements(input_map, caption, measurements); +} + +#endif + +// InstructionSets::RunAll callback. +void AddMeasurementsWithPrefix(const char* prefix, const char* target_name, + DurationsForInputs* input_map, void* context) { + std::string caption(prefix); + caption += target_name; + AddMeasurements(input_map, caption.c_str(), + static_cast(context)); +} + +#if BENCHMARK_SIP + +uint64_t RunSip(const void*, const size_t size) { + HH_ALIGNAS(16) const HH_U64 key2[2] = {0, 1}; + char in[kMaxBenchmarkInputSize]; + memcpy(in, &size, sizeof(size)); + return SipHash(key2, in, size); +} + +uint64_t RunSip13(const void*, const size_t size) { + HH_ALIGNAS(16) const HH_U64 key2[2] = {0, 1}; + char in[kMaxBenchmarkInputSize]; + memcpy(in, &size, sizeof(size)); + return SipHash13(key2, in, size); +} + +#endif + +#if BENCHMARK_SIP_TREE + +uint64_t RunSipTree(const void*, const size_t size) { + HH_ALIGNAS(32) const HH_U64 key4[4] = {0, 1, 2, 3}; + char in[kMaxBenchmarkInputSize]; + memcpy(in, &size, sizeof(size)); + return SipTreeHash(key4, in, size); +} + +uint64_t RunSipTree13(const void*, const size_t size) { + HH_ALIGNAS(32) const HH_U64 key4[4] = {0, 1, 2, 3}; + char in[kMaxBenchmarkInputSize]; + memcpy(in, &size, sizeof(size)); + return SipTreeHash13(key4, in, size); +} + +#endif + +#if BENCHMARK_FARM + +uint64_t RunFarm(const void*, const size_t size) { + char in[kMaxBenchmarkInputSize]; + memcpy(in, &size, sizeof(size)); + return farmhash::Fingerprint64(reinterpret_cast(in), size); +} + +#endif + +#if BENCHMARK_INTERNAL +uint64_t RunInternal(const void*, const size_t size) { + char in[kMaxBenchmarkInputSize]; + memcpy(in, &size, sizeof(size)); + return in[rand() % size]; +} +#endif + +void AddMeasurements(const std::vector& in_sizes, + Measurements* measurements) { + DurationsForInputs input_map(in_sizes.data(), in_sizes.size(), 40); +#if BENCHMARK_SIP + MeasureAndAdd(&input_map, "SipHash", &RunSip, measurements); + MeasureAndAdd(&input_map, "SipHash13", &RunSip13, measurements); +#endif + +#if BENCHMARK_SIP_TREE && defined(__AVX2__) + MeasureAndAdd(&input_map, "SipTreeHash", &RunSipTree, measurements); + MeasureAndAdd(&input_map, "SipTreeHash13", &RunSipTree13, measurements); +#endif + +#if BENCHMARK_FARM + MeasureAndAdd(&input_map, "Farm", &RunFarm, measurements); +#endif + +#if BENCHMARK_INTERNAL + MeasureAndAdd(&input_map, "Internal", &RunInternal, measurements); +#endif + +#if BENCHMARK_HIGHWAY + InstructionSets::RunAll( + &input_map, &AddMeasurementsWithPrefix, measurements); +#endif + +#if BENCHMARK_HIGHWAY_CAT + InstructionSets::RunAll( + &input_map, &AddMeasurementsWithPrefix, measurements); +#endif +} + +void PrintTable() { + const std::vector in_sizes = { + 7, 8, 31, 32, 63, 64, kMaxBenchmarkInputSize}; + Measurements measurements; + AddMeasurements(in_sizes, &measurements); + measurements.PrintTable(in_sizes); +} + +void PrintPlots() { + std::vector in_sizes; + for (int num_vectors = 0; num_vectors < 12; ++num_vectors) { + for (int remainder : {0, 9, 18, 27}) { + in_sizes.push_back(num_vectors * 32 + remainder); + assert(in_sizes.back() <= kMaxBenchmarkInputSize); + } + } + + Measurements measurements; + AddMeasurements(in_sizes, &measurements); + measurements.PrintPlots(); +} + +} // namespace +} // namespace highwayhash + +int main(int argc, char* argv[]) { + // No argument or t => table + if (argc < 2 || argv[1][0] == 't') { + highwayhash::PrintTable(); + } else if (argv[1][0] == 'p') { + highwayhash::PrintPlots(); + } + return 0; +} diff --git a/src/Native/libdero/include/highwayhash/c_bindings.cc b/src/Native/libdero/include/highwayhash/c_bindings.cc new file mode 100644 index 0000000000..54904e2d03 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/c_bindings.cc @@ -0,0 +1,35 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 "c_bindings.h" + +#include "highwayhash_target.h" +#include "instruction_sets.h" + +using highwayhash::InstructionSets; +using highwayhash::HighwayHash; + +extern "C" { + +// Ideally this would reside in highwayhash_target.cc, but that file is +// compiled multiple times and we must only define this function once. +uint64_t HighwayHash64(const HHKey key, const char* bytes, + const uint64_t size) { + HHResult64 result; + InstructionSets::Run(*reinterpret_cast(key), bytes, + size, &result); + return result; +} + +} // extern "C" diff --git a/src/Native/libdero/include/highwayhash/c_bindings.h b/src/Native/libdero/include/highwayhash/c_bindings.h new file mode 100644 index 0000000000..903aabc0fb --- /dev/null +++ b/src/Native/libdero/include/highwayhash/c_bindings.h @@ -0,0 +1,57 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_C_BINDINGS_H_ +#define HIGHWAYHASH_C_BINDINGS_H_ + +// C-callable function prototypes, documented in the other header files. + +#include + +#include "hh_types.h" + +#ifdef __cplusplus +extern "C" { + +// Bring the symbols out of the namespace. +using highwayhash::HHKey; +using highwayhash::HHPacket; +using highwayhash::HHResult128; +using highwayhash::HHResult256; +using highwayhash::HHResult64; +#endif + +uint64_t SipHashC(const uint64_t* key, const char* bytes, const uint64_t size); +uint64_t SipHash13C(const uint64_t* key, const char* bytes, + const uint64_t size); + +// Uses the best implementation of HighwayHash for the current CPU and +// calculates 64-bit hash of given data. +uint64_t HighwayHash64(const HHKey key, const char* bytes, const uint64_t size); + +// Defined by highwayhash_target.cc, which requires a _Target* suffix. +uint64_t HighwayHash64_TargetPortable(const HHKey key, const char* bytes, + const uint64_t size); +uint64_t HighwayHash64_TargetSSE41(const HHKey key, const char* bytes, + const uint64_t size); +uint64_t HighwayHash64_TargetAVX2(const HHKey key, const char* bytes, + const uint64_t size); +uint64_t HighwayHash64_TargetVSX(const HHKey key, const char* bytes, + const uint64_t size); + +#ifdef __cplusplus +} +#endif + +#endif // HIGHWAYHASH_C_BINDINGS_H_ diff --git a/src/Native/libdero/include/highwayhash/compiler_specific.h b/src/Native/libdero/include/highwayhash/compiler_specific.h new file mode 100644 index 0000000000..4789f9a610 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/compiler_specific.h @@ -0,0 +1,90 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_COMPILER_SPECIFIC_H_ +#define HIGHWAYHASH_COMPILER_SPECIFIC_H_ + +// WARNING: this is a "restricted" header because it is included from +// translation units compiled with different flags. This header and its +// dependencies must not define any function unless it is static inline and/or +// within namespace HH_TARGET_NAME. See arch_specific.h for details. + +// Compiler + +// #if is shorter and safer than #ifdef. *_VERSION are zero if not detected, +// otherwise 100 * major + minor version. Note that other packages check for +// #ifdef COMPILER_MSVC, so we cannot use that same name. + +#ifdef _MSC_VER +#define HH_MSC_VERSION _MSC_VER +#else +#define HH_MSC_VERSION 0 +#endif + +#ifdef __GNUC__ +#define HH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#else +#define HH_GCC_VERSION 0 +#endif + +#ifdef __clang__ +#define HH_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) +#else +#define HH_CLANG_VERSION 0 +#endif + +//----------------------------------------------------------------------------- + +#if HH_GCC_VERSION && HH_GCC_VERSION < 408 +#define HH_ALIGNAS(multiple) __attribute__((aligned(multiple))) +#else +#define HH_ALIGNAS(multiple) alignas(multiple) // C++11 +#endif + +#if HH_MSC_VERSION +#define HH_RESTRICT __restrict +#elif HH_GCC_VERSION +#define HH_RESTRICT __restrict__ +#else +#define HH_RESTRICT +#endif + +#if HH_MSC_VERSION +#define HH_INLINE __forceinline +#define HH_NOINLINE __declspec(noinline) +#else +#define HH_INLINE inline +#define HH_NOINLINE __attribute__((noinline)) +#endif + +#if HH_MSC_VERSION +// Unsupported, __assume is not the same. +#define HH_LIKELY(expr) expr +#define HH_UNLIKELY(expr) expr +#else +#define HH_LIKELY(expr) __builtin_expect(!!(expr), 1) +#define HH_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#endif + +#if HH_MSC_VERSION +#include +#pragma intrinsic(_ReadWriteBarrier) +#define HH_COMPILER_FENCE _ReadWriteBarrier() +#elif HH_GCC_VERSION +#define HH_COMPILER_FENCE asm volatile("" : : : "memory") +#else +#define HH_COMPILER_FENCE +#endif + +#endif // HIGHWAYHASH_COMPILER_SPECIFIC_H_ diff --git a/src/Native/libdero/include/highwayhash/data_parallel.h b/src/Native/libdero/include/highwayhash/data_parallel.h new file mode 100644 index 0000000000..d72afc953e --- /dev/null +++ b/src/Native/libdero/include/highwayhash/data_parallel.h @@ -0,0 +1,341 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_DATA_PARALLEL_H_ +#define HIGHWAYHASH_DATA_PARALLEL_H_ + +// Portable C++11 alternative to OpenMP for data-parallel computations: +// provides low-overhead ThreadPool, plus PerThread with support for reduction. + +#include +#include // find_if +#include +#include //NOLINT +#include +#include +#include +#include +#include //NOLINT +#include //NOLINT +#include +#include + +#define DATA_PARALLEL_CHECK(condition) \ + while (!(condition)) { \ + printf("data_parallel check failed at line %d\n", __LINE__); \ + abort(); \ + } + +namespace highwayhash { + +// Highly scalable thread pool, especially suitable for data-parallel +// computations in the fork-join model, where clients need to know when all +// tasks have completed. +// +// Thread pools usually store small numbers of heterogeneous tasks in a queue. +// When tasks are identical or differ only by an integer input parameter, it is +// much faster to store just one function of an integer parameter and call it +// for each value. +// +// This thread pool can efficiently load-balance millions of tasks using an +// atomic counter, thus avoiding per-task syscalls. With 48 hyperthreads and +// 1M tasks that add to an atomic counter, overall runtime is 10-20x higher +// when using std::async, and up to 200x for a queue-based ThreadPool. +// +// Usage: +// ThreadPool pool; +// pool.Run(0, 1000000, [](const int i) { Func1(i); }); +// // When Run returns, all of its tasks have finished. +// +// pool.RunTasks({Func2, Func3, Func4}); +// // The destructor waits until all worker threads have exited cleanly. +class ThreadPool { + public: + // Starts the given number of worker threads and blocks until they are ready. + // "num_threads" defaults to one per hyperthread. + explicit ThreadPool( + const int num_threads = std::thread::hardware_concurrency()) + : num_threads_(num_threads) { + DATA_PARALLEL_CHECK(num_threads_ > 0); + threads_.reserve(num_threads_); + for (int i = 0; i < num_threads_; ++i) { + threads_.emplace_back(ThreadFunc, this); + } + + padding_[0] = 0; // avoid unused member warning. + + WorkersReadyBarrier(); + } + + ThreadPool(const ThreadPool&) = delete; + ThreadPool& operator&(const ThreadPool&) = delete; + + // Waits for all threads to exit. + ~ThreadPool() { + StartWorkers(kWorkerExit); + + for (std::thread& thread : threads_) { + thread.join(); + } + } + + // Runs func(i) on worker thread(s) for every i in [begin, end). + // Not thread-safe - no two calls to Run and RunTasks may overlap. + // Subsequent calls will reuse the same threads. + // + // Precondition: 0 <= begin <= end. + template + void Run(const int begin, const int end, const Func& func) { + DATA_PARALLEL_CHECK(0 <= begin && begin <= end); + if (begin == end) { + return; + } + const WorkerCommand worker_command = (WorkerCommand(end) << 32) + begin; + // Ensure the inputs do not result in a reserved command. + DATA_PARALLEL_CHECK(worker_command != kWorkerWait); + DATA_PARALLEL_CHECK(worker_command != kWorkerExit); + + // If Func is large (many captures), this will allocate memory, but it is + // still slower to use a std::ref wrapper. + task_ = func; + num_reserved_.store(0); + + StartWorkers(worker_command); + WorkersReadyBarrier(); + } + + // Runs each task (closure, typically a lambda function) on worker thread(s). + // Not thread-safe - no two calls to Run and RunTasks may overlap. + // Subsequent calls will reuse the same threads. + // + // This is a more conventional interface for heterogeneous tasks that may be + // independent/unrelated. + void RunTasks(const std::vector>& tasks) { + Run(0, static_cast(tasks.size()), + [&tasks](const int i) { tasks[i](); }); + } + + // Statically (and deterministically) splits [begin, end) into ranges and + // calls "func" for each of them. Useful when "func" involves some overhead + // (e.g. for PerThread::Get or random seeding) that should be amortized over + // a range of values. "func" is void(int chunk, uint32_t begin, uint32_t end). + template + void RunRanges(const uint32_t begin, const uint32_t end, const Func& func) { + const uint32_t length = end - begin; + + // Use constant rather than num_threads_ for machine-independent splitting. + const uint32_t chunk = std::max(1U, (length + 127) / 128); + std::vector> ranges; // begin/end + ranges.reserve(length / chunk + 1); + for (uint32_t i = 0; i < length; i += chunk) { + ranges.emplace_back(begin + i, begin + std::min(i + chunk, length)); + } + + Run(0, static_cast(ranges.size()), [&ranges, func](const int i) { + func(i, ranges[i].first, ranges[i].second); + }); + } + + private: + // After construction and between calls to Run, workers are "ready", i.e. + // waiting on worker_start_cv_. They are "started" by sending a "command" + // and notifying all worker_start_cv_ waiters. (That is why all workers + // must be ready/waiting - otherwise, the notification will not reach all of + // them and the main thread waits in vain for them to report readiness.) + using WorkerCommand = uint64_t; + + // Special values; all others encode the begin/end parameters. + static constexpr WorkerCommand kWorkerWait = 0; + static constexpr WorkerCommand kWorkerExit = ~0ULL; + + void WorkersReadyBarrier() { + std::unique_lock lock(mutex_); + workers_ready_cv_.wait(lock, + [this]() { return workers_ready_ == num_threads_; }); + workers_ready_ = 0; + } + + // Precondition: all workers are ready. + void StartWorkers(const WorkerCommand worker_command) { + std::unique_lock lock(mutex_); + worker_start_command_ = worker_command; + // Workers will need this lock, so release it before they wake up. + lock.unlock(); + worker_start_cv_.notify_all(); + } + + // Attempts to reserve and perform some work from the global range of tasks, + // which is encoded within "command". Returns after all tasks are reserved. + static void RunRange(ThreadPool* self, const WorkerCommand command) { + const int begin = command & 0xFFFFFFFF; + const int end = command >> 32; + const int num_tasks = end - begin; + + // OpenMP introduced several "schedule" strategies: + // "single" (static assignment of exactly one chunk per thread): slower. + // "dynamic" (allocates k tasks at a time): competitive for well-chosen k. + // "guided" (allocates k tasks, decreases k): computing k = remaining/n + // is faster than halving k each iteration. We prefer this strategy + // because it avoids user-specified parameters. + + for (;;) { + const int num_reserved = self->num_reserved_.load(); + const int num_remaining = num_tasks - num_reserved; + const int my_size = std::max(num_remaining / (self->num_threads_ * 2), 1); + const int my_begin = begin + self->num_reserved_.fetch_add(my_size); + const int my_end = std::min(my_begin + my_size, begin + num_tasks); + // Another thread already reserved the last task. + if (my_begin >= my_end) { + break; + } + for (int i = my_begin; i < my_end; ++i) { + self->task_(i); + } + } + } + + static void ThreadFunc(ThreadPool* self) { + // Until kWorkerExit command received: + for (;;) { + std::unique_lock lock(self->mutex_); + // Notify main thread that this thread is ready. + if (++self->workers_ready_ == self->num_threads_) { + self->workers_ready_cv_.notify_one(); + } + RESUME_WAIT: + // Wait for a command. + self->worker_start_cv_.wait(lock); + const WorkerCommand command = self->worker_start_command_; + switch (command) { + case kWorkerWait: // spurious wakeup: + goto RESUME_WAIT; // lock still held, avoid incrementing ready. + case kWorkerExit: + return; // exits thread + } + + lock.unlock(); + RunRange(self, command); + } + } + + const int num_threads_; + + // Unmodified after ctor, but cannot be const because we call thread::join(). + std::vector threads_; + + std::mutex mutex_; // guards both cv and their variables. + std::condition_variable workers_ready_cv_; + int workers_ready_ = 0; + std::condition_variable worker_start_cv_; + WorkerCommand worker_start_command_; + + // Written by main thread, read by workers (after mutex lock/unlock). + std::function task_; + + // Updated by workers; alignment/padding avoids false sharing. + alignas(64) std::atomic num_reserved_{0}; + int padding_[15]; +}; + +// Thread-local storage with support for reduction (combining into one result). +// The "T" type must be unique to the call site because the list of threads' +// copies is a static member. (With knowledge of the underlying threads, we +// could eliminate this list and T allocations, but that is difficult to +// arrange and we prefer this to be usable independently of ThreadPool.) +// +// Usage: +// for (int i = 0; i < N; ++i) { +// // in each thread: +// T& my_copy = PerThread::Get(); +// my_copy.Modify(); +// +// // single-threaded: +// T& combined = PerThread::Reduce(); +// Use(combined); +// PerThread::Destroy(); +// } +// +// T is duck-typed and implements the following interface: +// +// // Returns true if T is default-initialized or Destroy was called without +// // any subsequent re-initialization. +// bool IsNull() const; +// +// // Releases any resources. Postcondition: IsNull() == true. +// void Destroy(); +// +// // Merges in data from "victim". Precondition: !IsNull() && !victim.IsNull(). +// void Assimilate(const T& victim); +template +class PerThread { + public: + // Returns reference to this thread's T instance (dynamically allocated, + // so its address is unique). Callers are responsible for any initialization + // beyond the default ctor. + static T& Get() { + static thread_local T* t; + if (t == nullptr) { + t = new T; + static std::mutex mutex; + std::lock_guard lock(mutex); + Threads().push_back(t); + } + return *t; + } + + // Returns vector of all per-thread T. Used inside Reduce() or by clients + // that require direct access to T instead of Assimilating them. + // Function wrapper avoids separate static member variable definition. + static std::vector& Threads() { + static std::vector threads; + return threads; + } + + // Returns the first non-null T after assimilating all other threads' T + // into it. Precondition: at least one non-null T exists (caller must have + // called Get() and initialized the result). + static T& Reduce() { + std::vector& threads = Threads(); + + // Find first non-null T + const auto it = std::find_if(threads.begin(), threads.end(), + [](const T* t) { return !t->IsNull(); }); + if (it == threads.end()) { + abort(); + } + T* const first = *it; + + for (const T* t : threads) { + if (t != first && !t->IsNull()) { + first->Assimilate(*t); + } + } + return *first; + } + + // Calls each thread's T::Destroy to release resources and/or prepare for + // reuse by the same threads/ThreadPool. Note that all T remain allocated + // (we need thread-independent pointers for iterating over each thread's T, + // and deleting them would leave dangling pointers in each thread, which is + // unacceptable because the same thread may call Get() again later.) + static void Destroy() { + for (T* t : Threads()) { + t->Destroy(); + } + } +}; + +} // namespace highwayhash + +#endif // HIGHWAYHASH_DATA_PARALLEL_H_ diff --git a/src/Native/libdero/include/highwayhash/data_parallel_benchmark.cc b/src/Native/libdero/include/highwayhash/data_parallel_benchmark.cc new file mode 100644 index 0000000000..87dc739394 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/data_parallel_benchmark.cc @@ -0,0 +1,157 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 +#include +#include //NOLINT +#include + +#include "testing/base/public/gunit.h" +#include "third_party/absl/container/btree_set.h" +#include "third_party/absl/time/clock.h" +#include "third_party/absl/time/time.h" +#include "arch_specific.h" +#include "data_parallel.h" +#include "thread/threadpool.h" + +namespace highwayhash { +namespace { + +constexpr int kBenchmarkTasks = 1000000; + +// Returns elapsed time [nanoseconds] for std::async. +double BenchmarkAsync(uint64_t* total) { + const absl::Time t0 = absl::Now(); + std::atomic sum1{0}; + std::atomic sum2{0}; + + std::vector> futures; + futures.reserve(kBenchmarkTasks); + for (int i = 0; i < kBenchmarkTasks; ++i) { + futures.push_back(std::async( + [&sum1, &sum2](const int i) { + sum1.fetch_add(i); + sum2.fetch_add(1); + }, + i)); + } + + for (auto& future : futures) { + future.get(); + } + + const absl::Time t1 = absl::Now(); + *total = sum1.load() + sum2.load(); + return absl::ToDoubleNanoseconds(t1 - t0); +} + +// Returns elapsed time [nanoseconds] for (atomic) ThreadPool. +double BenchmarkPoolA(uint64_t* total) { + const absl::Time t0 = absl::Now(); + std::atomic sum1{0}; + std::atomic sum2{0}; + + ThreadPool pool; + pool.Run(0, kBenchmarkTasks, [&sum1, &sum2](const int i) { + sum1.fetch_add(i); + sum2.fetch_add(1); + }); + + const absl::Time t1 = absl::Now(); + *total = sum1.load() + sum2.load(); + return absl::ToDoubleNanoseconds(t1 - t0); +} + +// Returns elapsed time [nanoseconds] for ::ThreadPool. +double BenchmarkPoolG(uint64_t* total) { + const absl::Time t0 = absl::Now(); + std::atomic sum1{0}; + std::atomic sum2{0}; + + { + ::ThreadPool pool(std::thread::hardware_concurrency()); + pool.StartWorkers(); + for (int i = 0; i < kBenchmarkTasks; ++i) { + pool.Schedule([&sum1, &sum2, i]() { + sum1.fetch_add(i); + sum2.fetch_add(1); + }); + } + } + + const absl::Time t1 = absl::Now(); + *total = sum1.load() + sum2.load(); + return absl::ToDoubleNanoseconds(t1 - t0); +} + +// Compares ThreadPool speed to std::async and ::ThreadPool. +TEST(DataParallelTest, Benchmarks) { + uint64_t sum1, sum2, sum3; + const double async_ns = BenchmarkAsync(&sum1); + const double poolA_ns = BenchmarkPoolA(&sum2); + const double poolG_ns = BenchmarkPoolG(&sum3); + + printf("Async %11.0f ns\nPoolA %11.0f ns\nPoolG %11.0f ns\n", async_ns, + poolA_ns, poolG_ns); + // baseline 20x, 10x with asan or msan, 5x with tsan + EXPECT_GT(async_ns, poolA_ns * 4); + // baseline 200x, 180x with asan, 70x with msan, 50x with tsan. + EXPECT_GT(poolG_ns, poolA_ns * 20); + + // Should reach same result. + EXPECT_EQ(sum1, sum2); + EXPECT_EQ(sum2, sum3); +} + +#if HH_ARCH_X64 +// Ensures multiple hardware threads are used (decided by the OS scheduler). +TEST(DataParallelTest, TestApicIds) { + for (int num_threads = 1; num_threads <= std::thread::hardware_concurrency(); + ++num_threads) { + ThreadPool pool(num_threads); + + std::mutex mutex; + absl::btree_set ids; + double total = 0.0; + pool.Run(0, 2 * num_threads, [&mutex, &ids, &total](const int i) { + // Useless computations to keep the processor busy so that threads + // can't just reuse the same processor. + double sum = 0.0; + for (int rep = 0; rep < 900 * (i + 30); ++rep) { + sum += pow(rep, 0.5); + } + + mutex.lock(); + ids.insert(ApicId()); + total += sum; + mutex.unlock(); + }); + + // No core ID / APIC ID available + if (num_threads > 1 && ids.size() == 1) { + EXPECT_EQ(0, *ids.begin()); + } else { + // (The Linux scheduler doesn't use all available HTs, but the + // computations should at least keep most cores busy.) + EXPECT_GT(ids.size() + 2, num_threads / 4); + } + + // (Ensure the busy-work is not elided.) + EXPECT_GT(total, 1E4); + } +} +#endif // HH_ARCH_X64 + +} // namespace +} // namespace highwayhash diff --git a/src/Native/libdero/include/highwayhash/data_parallel_test.cc b/src/Native/libdero/include/highwayhash/data_parallel_test.cc new file mode 100644 index 0000000000..02a0efb24e --- /dev/null +++ b/src/Native/libdero/include/highwayhash/data_parallel_test.cc @@ -0,0 +1,175 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 +#include + +#include "testing/base/public/gunit.h" +#include "data_parallel.h" + +namespace highwayhash { +namespace { + +int PopulationCount(uint64_t bits) { + int num_set = 0; + while (bits != 0) { + num_set += bits & 1; + bits >>= 1; + } + return num_set; +} + +std::atomic func_counts{0}; + +void Func2() { + usleep(200000); + func_counts.fetch_add(4); +} + +void Func3() { + usleep(300000); + func_counts.fetch_add(16); +} + +void Func4() { + usleep(400000); + func_counts.fetch_add(256); +} + +// Exercises the RunTasks feature (running arbitrary tasks/closures) +TEST(DataParallelTest, TestRunTasks) { + ThreadPool pool(4); + pool.RunTasks({Func2, Func3, Func4}); + EXPECT_EQ(276, func_counts.load()); +} + +// Ensures task parameter is in bounds, every parameter is reached, +// pool can be reused (multiple consecutive Run calls), pool can be destroyed +// (joining with its threads). +TEST(DataParallelTest, TestPool) { + for (int num_threads = 1; num_threads <= 18; ++num_threads) { + ThreadPool pool(num_threads); + for (int num_tasks = 0; num_tasks < 32; ++num_tasks) { + std::vector mementos(num_tasks, 0); + for (int begin = 0; begin < 32; ++begin) { + std::fill(mementos.begin(), mementos.end(), 0); + pool.Run(begin, begin + num_tasks, + [begin, num_tasks, &mementos](const int i) { + // Parameter is in the given range + EXPECT_GE(i, begin); + EXPECT_LT(i, begin + num_tasks); + + // Store mementos to be sure we visited each i. + mementos.at(i - begin) = 1000 + i; + }); + for (int i = begin; i < begin + num_tasks; ++i) { + EXPECT_EQ(1000 + i, mementos.at(i - begin)); + } + } + } + } +} + +TEST(DataParallelTest, TestRunRanges) { + for (int num_threads = 1; num_threads <= 18; ++num_threads) { + ThreadPool pool(num_threads); + for (int num_tasks = 0; num_tasks < 32; ++num_tasks) { + std::vector mementos(num_tasks, 0); + for (int begin = 0; begin < 32; ++begin) { + std::fill(mementos.begin(), mementos.end(), 0); + pool.RunRanges(begin, begin + num_tasks, + [begin, num_tasks, &mementos](const int chunk, + const uint32_t my_begin, + const uint32_t my_end) { + for (uint32_t i = my_begin; i < my_end; ++i) { + // Parameter is in the given range + EXPECT_GE(i, begin); + EXPECT_LT(i, begin + num_tasks); + + // Store mementos to be sure we visited each i. + mementos.at(i - begin) = 1000 + i; + } + }); + for (int i = begin; i < begin + num_tasks; ++i) { + EXPECT_EQ(1000 + i, mementos.at(i - begin)); + } + } + } + } +} + +// Ensures each of N threads processes exactly 1 of N tasks, i.e. the +// work distribution is perfectly fair for small counts. +TEST(DataParallelTest, TestSmallAssignments) { + for (int num_threads = 1; num_threads <= 64; ++num_threads) { + ThreadPool pool(num_threads); + + std::atomic counter{0}; + // (Avoid mutex because it may perturb the worker thread scheduling) + std::atomic id_bits{0}; + + pool.Run(0, num_threads, [&counter, num_threads, &id_bits](const int i) { + const int id = counter.fetch_add(1); + EXPECT_LT(id, num_threads); + uint64_t bits = id_bits.load(std::memory_order_relaxed); + while (!id_bits.compare_exchange_weak(bits, bits | (1ULL << id))) { + } + }); + + const int num_participants = PopulationCount(id_bits.load()); + EXPECT_EQ(num_threads, num_participants); + } +} + +// Test payload for PerThread. +struct CheckUniqueIDs { + bool IsNull() const { return false; } + void Destroy() { id_bits = 0; } + void Assimilate(const CheckUniqueIDs& victim) { + // Cannot overlap because each PerThread has unique bits. + EXPECT_EQ(0, id_bits & victim.id_bits); + id_bits |= victim.id_bits; + } + + uint64_t id_bits = 0; +}; + +// Ensures each thread has a PerThread instance, that they are successfully +// combined/reduced into a single result, and that reuse is possible after +// Destroy(). +TEST(DataParallelTest, TestPerThread) { + // We use a uint64_t bit array for convenience => no more than 64 threads. + const int max_threads = std::min(64U, std::thread::hardware_concurrency()); + for (int num_threads = 1; num_threads <= max_threads; ++num_threads) { + ThreadPool pool(num_threads); + + std::atomic counter{0}; + pool.Run(0, num_threads, [&counter, num_threads](const int i) { + const int id = counter.fetch_add(1); + EXPECT_LT(id, num_threads); + PerThread::Get().id_bits |= 1ULL << id; + }); + + // Verify each thread's bit is set. + const uint64_t all_bits = PerThread::Reduce().id_bits; + // Avoid shifting by 64 (undefined). + const uint64_t expected = + num_threads == 64 ? ~0ULL : (1ULL << num_threads) - 1; + EXPECT_EQ(expected, all_bits); + PerThread::Destroy(); + } +} + +} // namespace +} // namespace highwayhash diff --git a/src/Native/libdero/include/highwayhash/endianess.h b/src/Native/libdero/include/highwayhash/endianess.h new file mode 100644 index 0000000000..776a02fa21 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/endianess.h @@ -0,0 +1,108 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_ENDIANESS_H_ +#define HIGHWAYHASH_ENDIANESS_H_ + +// WARNING: this is a "restricted" header because it is included from +// translation units compiled with different flags. This header and its +// dependencies must not define any function unless it is static inline and/or +// within namespace HH_TARGET_NAME. See arch_specific.h for details. + +#include + +#if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) + + /* Someone has already included or equivalent. */ + +#elif defined(__LITTLE_ENDIAN__) + +# define HH_IS_LITTLE_ENDIAN 1 +# define HH_IS_BIG_ENDIAN 0 +# ifdef __BIG_ENDIAN__ +# error "Platform is both little and big endian?" +# endif + +#elif defined(__BIG_ENDIAN__) + +# define HH_IS_LITTLE_ENDIAN 0 +# define HH_IS_BIG_ENDIAN 1 + +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ + defined(__ORDER_LITTLE_ENDIAN__) + +# define HH_IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +# define HH_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + +#elif defined(__linux__) || defined(__CYGWIN__) || defined( __GNUC__ ) || \ + defined( __GNU_LIBRARY__ ) + +# include + +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || \ + defined(__DragonFly__) + +# include + +#elif defined(_WIN32) + +#define HH_IS_LITTLE_ENDIAN 1 +#define HH_IS_BIG_ENDIAN 0 + +#else + +# error "Unsupported platform. Cannot determine byte order." + +#endif + + +#ifndef HH_IS_LITTLE_ENDIAN +# define HH_IS_LITTLE_ENDIAN (BYTE_ORDER == LITTLE_ENDIAN) +# define HH_IS_BIG_ENDIAN (BYTE_ORDER == BIG_ENDIAN) +#endif + + +namespace highwayhash { + +#if HH_IS_LITTLE_ENDIAN + +static inline uint32_t le32_from_host(uint32_t x) { return x; } +static inline uint32_t host_from_le32(uint32_t x) { return x; } +static inline uint64_t le64_from_host(uint64_t x) { return x; } +static inline uint64_t host_from_le64(uint64_t x) { return x; } + +#elif !HH_IS_BIG_ENDIAN + +# error "Unsupported byte order." + +#elif defined(_WIN16) || defined(_WIN32) || defined(_WIN64) + +#include +static inline uint32_t host_from_le32(uint32_t x) { return _byteswap_ulong(x); } +static inline uint32_t le32_from_host(uint32_t x) { return _byteswap_ulong(x); } +static inline uint64_t host_from_le64(uint64_t x) { return _byteswap_uint64(x);} +static inline uint64_t le64_from_host(uint64_t x) { return _byteswap_uint64(x);} + +#else + +static inline uint32_t host_from_le32(uint32_t x) {return __builtin_bswap32(x);} +static inline uint32_t le32_from_host(uint32_t x) {return __builtin_bswap32(x);} +static inline uint64_t host_from_le64(uint64_t x) {return __builtin_bswap64(x);} +static inline uint64_t le64_from_host(uint64_t x) {return __builtin_bswap64(x);} + +#endif + +} // namespace highwayhash + +#endif // HIGHWAYHASH_ENDIANESS_H_ diff --git a/src/Native/libdero/include/highwayhash/example.cc b/src/Native/libdero/include/highwayhash/example.cc new file mode 100644 index 0000000000..0fd15a7237 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/example.cc @@ -0,0 +1,40 @@ +// Minimal usage example: prints a hash. Tested on x86, ppc, arm. + +#include +#include +#include + +#include "highwayhash.h" + +using namespace highwayhash; + +int main(int argc, char* argv[]) { + // We read from the args on purpose, to ensure a compile time constant will + // not be used, for verifying assembly on the supported platforms. + if (argc != 2) { + std::cout << "Please provide 1 argument with a text to hash" << std::endl; + return 1; + } + + // Please use a different key to ensure your hashes aren't identical. + HH_ALIGNAS(32) const HHKey key = {1, 2, 3, 4}; + + // Aligning inputs to 32 bytes may help but is not required. + const char* in = argv[1]; + const size_t size = strlen(in); + + // Type determines the hash size; can also be HHResult128 or HHResult256. + HHResult64 result; + + // HH_TARGET_PREFERRED expands to the best specialization available for the + // CPU detected via compiler flags (e.g. AVX2 #ifdef __AVX2__). + HHStateT state(key); + HighwayHashT(&state, in, size, &result); + std::cout << "Hash : " << result << std::endl; + + HighwayHashCatT cat(key); + cat.Append(in, size); + cat.Finalize(&result); + std::cout << "HashCat: " << result << std::endl; + return 0; +} diff --git a/src/Native/libdero/include/highwayhash/hh_avx2.cc b/src/Native/libdero/include/highwayhash/hh_avx2.cc new file mode 100644 index 0000000000..95c3334f1d --- /dev/null +++ b/src/Native/libdero/include/highwayhash/hh_avx2.cc @@ -0,0 +1,19 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +// WARNING: this is a "restricted" source file; avoid including any headers +// unless they are also restricted. See arch_specific.h for details. + +#define HH_TARGET_NAME AVX2 +#include "highwayhash_target.cc" diff --git a/src/Native/libdero/include/highwayhash/hh_avx2.h b/src/Native/libdero/include/highwayhash/hh_avx2.h new file mode 100644 index 0000000000..3fe2929cc1 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/hh_avx2.h @@ -0,0 +1,381 @@ +// Copyright 2015-2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_HH_AVX2_H_ +#define HIGHWAYHASH_HH_AVX2_H_ + +// WARNING: this is a "restricted" header because it is included from +// translation units compiled with different flags. This header and its +// dependencies must not define any function unless it is static inline and/or +// within namespace HH_TARGET_NAME. See arch_specific.h for details. + +#include "arch_specific.h" +#include "compiler_specific.h" +#include "hh_buffer.h" +#include "hh_types.h" +#include "load3.h" +#include "vector128.h" +#include "vector256.h" + +// For auto-dependency generation, we need to include all headers but not their +// contents (otherwise compilation fails because -mavx2 is not specified). +#ifndef HH_DISABLE_TARGET_SPECIFIC + +namespace highwayhash { +// See vector128.h for why this namespace is necessary; matching it here makes +// it easier use the vector128 symbols, but requires textual inclusion. +namespace HH_TARGET_NAME { + +class HHStateAVX2 { + public: + explicit HH_INLINE HHStateAVX2(const HHKey key_lanes) { Reset(key_lanes); } + + HH_INLINE void Reset(const HHKey key_lanes) { + // "Nothing up my sleeve" numbers, concatenated hex digits of Pi from + // http://www.numberworld.org/digits/Pi/, retrieved Feb 22, 2016. + // + // We use this python code to generate the fourth number to have + // more even mixture of bits: + /* +def x(a,b,c): + retval = 0 + for i in range(64): + count = ((a >> i) & 1) + ((b >> i) & 1) + ((c >> i) & 1) + if (count <= 1): + retval |= 1 << i + return retval + */ + const V4x64U init0(0x243f6a8885a308d3ull, 0x13198a2e03707344ull, + 0xa4093822299f31d0ull, 0xdbe6d5d5fe4cce2full); + const V4x64U init1(0x452821e638d01377ull, 0xbe5466cf34e90c6cull, + 0xc0acf169b5f18a8cull, 0x3bd39e10cb0ef593ull); + const V4x64U key = LoadUnaligned(key_lanes); + v0 = key ^ init0; + v1 = Rotate64By32(key) ^ init1; + mul0 = init0; + mul1 = init1; + } + + HH_INLINE void Update(const HHPacket& packet_bytes) { + const uint64_t* HH_RESTRICT packet = + reinterpret_cast(packet_bytes); + Update(LoadUnaligned(packet)); + } + + HH_INLINE void UpdateRemainder(const char* bytes, const size_t size_mod32) { + // 'Length padding' differentiates zero-valued inputs that have the same + // size/32. mod32 is sufficient because each Update behaves as if a + // counter were injected, because the state is large and mixed thoroughly. + const V8x32U size256( + _mm256_broadcastd_epi32(_mm_cvtsi64_si128(size_mod32))); + // Equivalent to storing size_mod32 in packet. + v0 += V4x64U(size256); + // Boosts the avalanche effect of mod32. + v1 = Rotate32By(v1, size256); + + const char* remainder = bytes + (size_mod32 & ~3); + const size_t size_mod4 = size_mod32 & 3; + + const V4x32U size(_mm256_castsi256_si128(size256)); + + // (Branching is faster than a single _mm256_maskload_epi32.) + if (HH_UNLIKELY(size_mod32 & 16)) { // 16..31 bytes left + const V4x32U packetL = + LoadUnaligned(reinterpret_cast(bytes)); + + const V4x32U int_mask = IntMask<16>()(size); + const V4x32U int_lanes = MaskedLoadInt(bytes + 16, int_mask); + const uint32_t last4 = + Load3()(Load3::AllowReadBeforeAndReturn(), remainder, size_mod4); + + // The upper four bytes of packetH are zero, so insert there. + const V4x32U packetH(_mm_insert_epi32(int_lanes, last4, 3)); + Update(packetH, packetL); + } else { // size_mod32 < 16 + const V4x32U int_mask = IntMask<0>()(size); + const V4x32U packetL = MaskedLoadInt(bytes, int_mask); + const uint64_t last3 = + Load3()(Load3::AllowUnordered(), remainder, size_mod4); + + // Rather than insert into packetL[3], it is faster to initialize + // the otherwise empty packetH. + const V4x32U packetH(_mm_cvtsi64_si128(last3)); + Update(packetH, packetL); + } + } + + HH_INLINE void Finalize(HHResult64* HH_RESTRICT result) { + // Mix together all lanes. It is slightly better to permute v0 than v1; + // it will be added to v1. + Update(Permute(v0)); + Update(Permute(v0)); + Update(Permute(v0)); + Update(Permute(v0)); + + const V2x64U sum0(_mm256_castsi256_si128(v0 + mul0)); + const V2x64U sum1(_mm256_castsi256_si128(v1 + mul1)); + const V2x64U hash = sum0 + sum1; + // Each lane is sufficiently mixed, so just truncate to 64 bits. + _mm_storel_epi64(reinterpret_cast<__m128i*>(result), hash); + } + + HH_INLINE void Finalize(HHResult128* HH_RESTRICT result) { + for (int n = 0; n < 6; n++) { + Update(Permute(v0)); + } + + const V2x64U sum0(_mm256_castsi256_si128(v0 + mul0)); + const V2x64U sum1(_mm256_extracti128_si256(v1 + mul1, 1)); + const V2x64U hash = sum0 + sum1; + _mm_storeu_si128(reinterpret_cast<__m128i*>(result), hash); + } + + HH_INLINE void Finalize(HHResult256* HH_RESTRICT result) { + for (int n = 0; n < 10; n++) { + Update(Permute(v0)); + } + + const V4x64U sum0 = v0 + mul0; + const V4x64U sum1 = v1 + mul1; + const V4x64U hash = ModularReduction(sum1, sum0); + StoreUnaligned(hash, &(*result)[0]); + } + + // "buffer" must be 32-byte aligned. + static HH_INLINE void ZeroInitialize(char* HH_RESTRICT buffer) { + const __m256i zero = _mm256_setzero_si256(); + _mm256_store_si256(reinterpret_cast<__m256i*>(buffer), zero); + } + + // "buffer" must be 32-byte aligned. + static HH_INLINE void CopyPartial(const char* HH_RESTRICT from, + const size_t size_mod32, + char* HH_RESTRICT buffer) { + const V4x32U size(size_mod32); + const uint32_t* const HH_RESTRICT from_u32 = + reinterpret_cast(from); + uint32_t* const HH_RESTRICT buffer_u32 = + reinterpret_cast(buffer); + if (HH_UNLIKELY(size_mod32 & 16)) { // Copying 16..31 bytes + const V4x32U inL = LoadUnaligned(from_u32); + Store(inL, buffer_u32); + const V4x32U inH = Load0To16<16, Load3::AllowReadBefore>( + from + 16, size_mod32 - 16, size); + Store(inH, buffer_u32 + V4x32U::N); + } else { // Copying 0..15 bytes + const V4x32U inL = Load0To16<>(from, size_mod32, size); + Store(inL, buffer_u32); + // No need to change upper 16 bytes of buffer. + } + } + + // "buffer" must be 32-byte aligned. + static HH_INLINE void AppendPartial(const char* HH_RESTRICT from, + const size_t size_mod32, + char* HH_RESTRICT buffer, + const size_t buffer_valid) { + const V4x32U size(size_mod32); + uint32_t* const HH_RESTRICT buffer_u32 = + reinterpret_cast(buffer); + // buffer_valid + size <= 32 => appending 0..16 bytes inside upper 16 bytes. + if (HH_UNLIKELY(buffer_valid & 16)) { + const V4x32U suffix = Load0To16<>(from, size_mod32, size); + const V4x32U bufferH = Load(buffer_u32 + V4x32U::N); + const V4x32U outH = Concatenate(bufferH, buffer_valid - 16, suffix); + Store(outH, buffer_u32 + V4x32U::N); + } else { // Appending 0..32 bytes starting at offset 0..15. + const V4x32U bufferL = Load(buffer_u32); + const V4x32U suffixL = Load0To16<>(from, size_mod32, size); + const V4x32U outL = Concatenate(bufferL, buffer_valid, suffixL); + Store(outL, buffer_u32); + const size_t offsetH = sizeof(V4x32U) - buffer_valid; + // Do we have enough input to start filling the upper 16 buffer bytes? + if (size_mod32 > offsetH) { + const size_t sizeH = size_mod32 - offsetH; + const V4x32U outH = Load0To16<>(from + offsetH, sizeH, V4x32U(sizeH)); + Store(outH, buffer_u32 + V4x32U::N); + } + } + } + + // "buffer" must be 32-byte aligned. + HH_INLINE void AppendAndUpdate(const char* HH_RESTRICT from, + const size_t size_mod32, + const char* HH_RESTRICT buffer, + const size_t buffer_valid) { + const V4x32U size(size_mod32); + const uint32_t* const HH_RESTRICT buffer_u32 = + reinterpret_cast(buffer); + // buffer_valid + size <= 32 => appending 0..16 bytes inside upper 16 bytes. + if (HH_UNLIKELY(buffer_valid & 16)) { + const V4x32U suffix = Load0To16<>(from, size_mod32, size); + const V4x32U packetL = Load(buffer_u32); + const V4x32U bufferH = Load(buffer_u32 + V4x32U::N); + const V4x32U packetH = Concatenate(bufferH, buffer_valid - 16, suffix); + Update(packetH, packetL); + } else { // Appending 0..32 bytes starting at offset 0..15. + const V4x32U bufferL = Load(buffer_u32); + const V4x32U suffixL = Load0To16<>(from, size_mod32, size); + const V4x32U packetL = Concatenate(bufferL, buffer_valid, suffixL); + const size_t offsetH = sizeof(V4x32U) - buffer_valid; + V4x32U packetH = packetL - packetL; + // Do we have enough input to start filling the upper 16 packet bytes? + if (size_mod32 > offsetH) { + const size_t sizeH = size_mod32 - offsetH; + packetH = Load0To16<>(from + offsetH, sizeH, V4x32U(sizeH)); + } + + Update(packetH, packetL); + } + } + + private: + static HH_INLINE V4x32U MaskedLoadInt(const char* from, + const V4x32U& int_mask) { + // No faults will be raised when reading n=0..3 ints from "from" provided + // int_mask[n] = 0. + const int* HH_RESTRICT int_from = reinterpret_cast(from); + return V4x32U(_mm_maskload_epi32(int_from, int_mask)); + } + + // Loads <= 16 bytes without accessing any byte outside [from, from + size). + // from[i] is loaded into lane i; from[i >= size] is undefined. + template + static HH_INLINE V4x32U Load0To16(const char* from, const size_t size_mod32, + const V4x32U& size) { + const char* remainder = from + (size_mod32 & ~3); + const uint64_t last3 = Load3()(Load3Policy(), remainder, size_mod32 & 3); + const V4x32U int_mask = IntMask()(size); + const V4x32U int_lanes = MaskedLoadInt(from, int_mask); + return Insert4AboveMask(last3, int_mask, int_lanes); + } + + static HH_INLINE V4x64U Rotate64By32(const V4x64U& v) { + return V4x64U(_mm256_shuffle_epi32(v, _MM_SHUFFLE(2, 3, 0, 1))); + } + + // Rotates 32-bit lanes by "count" bits. + static HH_INLINE V4x64U Rotate32By(const V4x64U& v, const V8x32U& count) { + // Use variable shifts because sll_epi32 has 4 cycle latency (presumably + // to broadcast the shift count). + const V4x64U shifted_left(_mm256_sllv_epi32(v, count)); + const V4x64U shifted_right(_mm256_srlv_epi32(v, V8x32U(32) - count)); + return shifted_left | shifted_right; + } + + static HH_INLINE V4x64U Permute(const V4x64U& v) { + // For complete mixing, we need to swap the upper and lower 128-bit halves; + // we also swap all 32-bit halves. This is faster than extracti128 plus + // inserti128 followed by Rotate64By32. + const V4x64U indices(0x0000000200000003ull, 0x0000000000000001ull, + 0x0000000600000007ull, 0x0000000400000005ull); + return V4x64U(_mm256_permutevar8x32_epi32(v, indices)); + } + + static HH_INLINE V4x64U MulLow32(const V4x64U& a, const V4x64U& b) { + return V4x64U(_mm256_mul_epu32(a, b)); + } + + static HH_INLINE V4x64U ZipperMerge(const V4x64U& v) { + // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to + // varying degrees. In descending order of goodness, bytes + // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32. + // As expected, the upper and lower bytes are much worse. + // For each 64-bit lane, our objectives are: + // 1) maximizing and equalizing total goodness across the four lanes. + // 2) mixing with bytes from the neighboring lane (AVX-2 makes it difficult + // to cross the 128-bit wall, but PermuteAndUpdate takes care of that); + // 3) placing the worst bytes in the upper 32 bits because those will not + // be used in the next 32x32 multiplication. + const uint64_t hi = 0x070806090D0A040Bull; + const uint64_t lo = 0x000F010E05020C03ull; + return V4x64U(_mm256_shuffle_epi8(v, V4x64U(hi, lo, hi, lo))); + } + + // Updates four hash lanes in parallel by injecting four 64-bit packets. + HH_INLINE void Update(const V4x64U& packet) { + v1 += packet; + v1 += mul0; + mul0 ^= MulLow32(v1, v0 >> 32); + HH_COMPILER_FENCE; + v0 += mul1; + mul1 ^= MulLow32(v0, v1 >> 32); + HH_COMPILER_FENCE; + v0 += ZipperMerge(v1); + v1 += ZipperMerge(v0); + } + + HH_INLINE void Update(const V4x32U& packetH, const V4x32U& packetL) { + const __m256i packetL256 = _mm256_castsi128_si256(packetL); + Update(V4x64U(_mm256_inserti128_si256(packetL256, packetH, 1))); + } + + // XORs a << 1 and a << 2 into *out after clearing the upper two bits of a. + // Also does the same for the upper 128 bit lane "b". Bit shifts are only + // possible on independent 64-bit lanes. We therefore insert the upper bits + // of a[0] that were lost into a[1]. Thanks to D. Lemire for helpful comments! + static HH_INLINE void XorByShift128Left12(const V4x64U& ba, + V4x64U* HH_RESTRICT out) { + const V4x64U zero = ba ^ ba; + const V4x64U top_bits2 = ba >> (64 - 2); + const V4x64U ones = ba == ba; // FF .. FF + const V4x64U shifted1_unmasked = ba + ba; // (avoids needing port0) + HH_COMPILER_FENCE; + + // Only the lower halves of top_bits1's 128 bit lanes will be used, so we + // can compute it before clearing the upper two bits of ba. + const V4x64U top_bits1 = ba >> (64 - 1); + const V4x64U upper_8bytes(_mm256_slli_si256(ones, 8)); // F 0 F 0 + const V4x64U shifted2 = shifted1_unmasked + shifted1_unmasked; + HH_COMPILER_FENCE; + + const V4x64U upper_bit_of_128 = upper_8bytes << 63; // 80..00 80..00 + const V4x64U new_low_bits2(_mm256_unpacklo_epi64(zero, top_bits2)); + *out ^= shifted2; + HH_COMPILER_FENCE; + + // The result must be as if the upper two bits of the input had been clear, + // otherwise we're no longer computing a reduction. + const V4x64U shifted1 = AndNot(upper_bit_of_128, shifted1_unmasked); + *out ^= new_low_bits2; + HH_COMPILER_FENCE; + + const V4x64U new_low_bits1(_mm256_unpacklo_epi64(zero, top_bits1)); + *out ^= shifted1; + + *out ^= new_low_bits1; + } + + // Modular reduction by the irreducible polynomial (x^128 + x^2 + x). + // Input: two 256-bit numbers a3210 and b3210, interleaved in 2 vectors. + // The upper and lower 128-bit halves are processed independently. + static HH_INLINE V4x64U ModularReduction(const V4x64U& b32a32, + const V4x64U& b10a10) { + // See Lemire, https://arxiv.org/pdf/1503.03465v8.pdf. + V4x64U out = b10a10; + XorByShift128Left12(b32a32, &out); + return out; + } + + V4x64U v0; + V4x64U v1; + V4x64U mul0; + V4x64U mul1; +}; + +} // namespace HH_TARGET_NAME +} // namespace highwayhash + +#endif // HH_DISABLE_TARGET_SPECIFIC +#endif // HIGHWAYHASH_HH_AVX2_H_ diff --git a/src/Native/libdero/include/highwayhash/hh_buffer.h b/src/Native/libdero/include/highwayhash/hh_buffer.h new file mode 100644 index 0000000000..02a64a2abc --- /dev/null +++ b/src/Native/libdero/include/highwayhash/hh_buffer.h @@ -0,0 +1,116 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_HH_BUFFER_H_ +#define HIGHWAYHASH_HH_BUFFER_H_ + +// Helper functions used by hh_avx2 and hh_sse41. + +// WARNING: this is a "restricted" header because it is included from +// translation units compiled with different flags. This header and its +// dependencies must not define any function unless it is static inline and/or +// within namespace HH_TARGET_NAME. See arch_specific.h for details. + +#if HH_TARGET == HH_TARGET_NEON +#include "vector_neon.h" +#else +#include "vector128.h" +#endif + +// For auto-dependency generation, we need to include all headers but not their +// contents (otherwise compilation fails because -msse4.1 is not specified). +#ifndef HH_DISABLE_TARGET_SPECIFIC + +namespace highwayhash { +// To prevent ODR violations when including this from multiple translation +// units (TU) that are compiled with different flags, the contents must reside +// in a namespace whose name is unique to the TU. NOTE: this behavior is +// incompatible with precompiled modules and requires textual inclusion instead. +namespace HH_TARGET_NAME { + +template +struct IntMask {}; // primary template + +template <> +struct IntMask<0> { + // Returns 32-bit lanes : ~0U if that lane can be loaded given "size" bytes. + // Typical case: size = 0..16, nothing deducted. + HH_INLINE V4x32U operator()(const V4x32U& size) const { + // Lane n is valid if size >= (n + 1) * 4; subtract one because we only have + // greater-than comparisons and don't want a negated mask. +#if HH_TARGET == HH_TARGET_NEON + return V4x32U(vcgtq_u32(size, V4x32U(15, 11, 7, 3))); +#else + return V4x32U(_mm_cmpgt_epi32(size, V4x32U(15, 11, 7, 3))); +#endif + } +}; + +template <> +struct IntMask<16> { + // "size" is 16..31; this is for loading the upper half of a packet, so + // effectively deduct 16 from size by changing the comparands. + HH_INLINE V4x32U operator()(const V4x32U& size) const { +#if HH_TARGET == HH_TARGET_NEON + return V4x32U(vcgtq_u32(size, V4x32U(31, 27, 23, 19))); +#else + return V4x32U(_mm_cmpgt_epi32(size, V4x32U(31, 27, 23, 19))); +#endif + } +}; + +// Inserts "bytes4" into "prev" at the lowest i such that mask[i] = 0. +// Assumes prev[j] == 0 if mask[j] = 0. +HH_INLINE V4x32U Insert4AboveMask(const uint32_t bytes4, const V4x32U& mask, + const V4x32U& prev) { + // There is no 128-bit shift by a variable count. Using shuffle_epi8 with a + // control mask requires a table lookup. We know the shift count is a + // multiple of 4 bytes, so we can broadcastd_epi32 and clear all lanes except + // those where mask != 0. This works because any upper output lanes need not + // be zero. + return prev | AndNot(mask, V4x32U(bytes4)); +} + +#if HH_TARGET == HH_TARGET_AVX2 +// Shifts "suffix" left by "prefix_len" = 0..15 bytes, clears upper bytes of +// "prefix", and returns the merged/concatenated bytes. +HH_INLINE V4x32U Concatenate(const V4x32U& prefix, const size_t prefix_len, + const V4x32U& suffix) { + static const uint64_t table[V16x8U::N][V2x64U::N] = { + {0x0706050403020100ull, 0x0F0E0D0C0B0A0908ull}, + {0x06050403020100FFull, 0x0E0D0C0B0A090807ull}, + {0x050403020100FFFFull, 0x0D0C0B0A09080706ull}, + {0x0403020100FFFFFFull, 0x0C0B0A0908070605ull}, + {0x03020100FFFFFFFFull, 0x0B0A090807060504ull}, + {0x020100FFFFFFFFFFull, 0x0A09080706050403ull}, + {0x0100FFFFFFFFFFFFull, 0x0908070605040302ull}, + {0x00FFFFFFFFFFFFFFull, 0x0807060504030201ull}, + {0xFFFFFFFFFFFFFFFFull, 0x0706050403020100ull}, + {0xFFFFFFFFFFFFFFFFull, 0x06050403020100FFull}, + {0xFFFFFFFFFFFFFFFFull, 0x050403020100FFFFull}, + {0xFFFFFFFFFFFFFFFFull, 0x0403020100FFFFFFull}, + {0xFFFFFFFFFFFFFFFFull, 0x03020100FFFFFFFFull}, + {0xFFFFFFFFFFFFFFFFull, 0x020100FFFFFFFFFFull}, + {0xFFFFFFFFFFFFFFFFull, 0x0100FFFFFFFFFFFFull}, + {0xFFFFFFFFFFFFFFFFull, 0x00FFFFFFFFFFFFFFull}}; + const V2x64U control = Load(&table[prefix_len][0]); + const V2x64U shifted_suffix(_mm_shuffle_epi8(suffix, control)); + return V4x32U(_mm_blendv_epi8(shifted_suffix, prefix, control)); +} +#endif +} // namespace HH_TARGET_NAME +} // namespace highwayhash + +#endif // HH_DISABLE_TARGET_SPECIFIC +#endif // HIGHWAYHASH_HH_BUFFER_H_ diff --git a/src/Native/libdero/include/highwayhash/hh_neon.cc b/src/Native/libdero/include/highwayhash/hh_neon.cc new file mode 100644 index 0000000000..b8a190b6b2 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/hh_neon.cc @@ -0,0 +1,22 @@ +// Copyright 2017-2019 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +// WARNING: this is a "restricted" source file; avoid including any headers +// unless they are also restricted. See arch_specific.h for details. + +#define HH_TARGET_NAME NEON +// GCC 4.5.4 only defines the former; 5.4 defines both. +#if defined(__ARM_NEON__) || defined(__ARM_NEON) +#include "highwayhash_target.cc" +#endif diff --git a/src/Native/libdero/include/highwayhash/hh_neon.h b/src/Native/libdero/include/highwayhash/hh_neon.h new file mode 100644 index 0000000000..57efabdea8 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/hh_neon.h @@ -0,0 +1,335 @@ +// Copyright 2015-2019 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_HH_NEON_H_ +#define HIGHWAYHASH_HH_NEON_H_ + +// WARNING: this is a "restricted" header because it is included from +// translation units compiled with different flags. This header and its +// dependencies must not define any function unless it is static inline and/or +// within namespace HH_TARGET_NAME. See arch_specific.h for details. + +#include "arch_specific.h" +#include "compiler_specific.h" +#include "hh_buffer.h" +#include "hh_types.h" +#include "load3.h" +#include "vector_neon.h" + +// For auto-dependency generation, we need to include all headers but not their +// contents. +#ifndef HH_DISABLE_TARGET_SPECIFIC + +namespace highwayhash { + +// See vector_neon.h for why this namespace is necessary; matching it here makes +// it easier use the vector_neon symbols, but requires textual inclusion. +namespace HH_TARGET_NAME { + +// J-lanes tree hashing: see https://doi.org/10.4236/jis.2014.53010 +// Uses the same method that SSE4.1 uses, only with NEON used instead. +class HHStateNEON { + public: + explicit HH_INLINE HHStateNEON(const HHKey key) { Reset(key); } + + HH_INLINE void Reset(const HHKey key) { + // "Nothing up my sleeve numbers"; see HHStateTAVX2. + const V2x64U init0L(0xa4093822299f31d0ull, 0xdbe6d5d5fe4cce2full); + const V2x64U init0H(0x243f6a8885a308d3ull, 0x13198a2e03707344ull); + const V2x64U init1L(0xc0acf169b5f18a8cull, 0x3bd39e10cb0ef593ull); + const V2x64U init1H(0x452821e638d01377ull, 0xbe5466cf34e90c6cull); + const V2x64U keyL = LoadUnaligned(key + 0); + const V2x64U keyH = LoadUnaligned(key + 2); + v0L = keyL ^ init0L; + v0H = keyH ^ init0H; + v1L = Rotate64By32(keyL) ^ init1L; + v1H = Rotate64By32(keyH) ^ init1H; + mul0L = init0L; + mul0H = init0H; + mul1L = init1L; + mul1H = init1H; + } + + HH_INLINE void Update(const HHPacket& packet_bytes) { + const uint64_t* HH_RESTRICT packet = + reinterpret_cast(packet_bytes); + const V2x64U packetL = LoadUnaligned(packet + 0); + const V2x64U packetH = LoadUnaligned(packet + 2); + Update(packetH, packetL); + } + + HH_INLINE void UpdateRemainder(const char* bytes, const size_t size_mod32) { + // 'Length padding' differentiates zero-valued inputs that have the same + // size/32. mod32 is sufficient because each Update behaves as if a + // counter were injected, because the state is large and mixed thoroughly. + + // We can't use vshl/vsra because it needs a constant expression. + // In order to do this right now, we would need a switch statement. + const int32x4_t vsize_mod32(vdupq_n_s32(static_cast(size_mod32))); + // -32 - size_mod32 + const int32x4_t shift_right_amt = + vdupq_n_s32(static_cast(size_mod32) + (~32 + 1)); + // Equivalent to storing size_mod32 in packet. + v0L += V2x64U(vreinterpretq_u64_s32(vsize_mod32)); + v0H += V2x64U(vreinterpretq_u64_s32(vsize_mod32)); + + // Boosts the avalanche effect of mod32. + v1L = V2x64U(vreinterpretq_u64_u32( + vorrq_u32(vshlq_u32(vreinterpretq_u32_u64(v1L), vsize_mod32), + vshlq_u32(vreinterpretq_u32_u64(v1L), shift_right_amt)))); + v1H = V2x64U(vreinterpretq_u64_u32( + vorrq_u32(vshlq_u32(vreinterpretq_u32_u64(v1H), vsize_mod32), + vshlq_u32(vreinterpretq_u32_u64(v1H), shift_right_amt)))); + + const size_t size_mod4 = size_mod32 & 3; + const char* HH_RESTRICT remainder = bytes + (size_mod32 & ~3); + + if (HH_UNLIKELY(size_mod32 & 16)) { // 16..31 bytes left + const V2x64U packetL = + LoadUnaligned(reinterpret_cast(bytes)); + + V2x64U packetH = LoadMultipleOfFour(bytes + 16, size_mod32); + + const uint32_t last4 = + Load3()(Load3::AllowReadBeforeAndReturn(), remainder, size_mod4); + + // The upper four bytes of packetH are zero, so insert there. + packetH = V2x64U(vreinterpretq_u64_u32( + vsetq_lane_u32(last4, vreinterpretq_u32_u64(packetH), 3))); + Update(packetH, packetL); + } else { // size_mod32 < 16 + const V2x64U packetL = LoadMultipleOfFour(bytes, size_mod32); + + const uint64_t last4 = + Load3()(Load3::AllowUnordered(), remainder, size_mod4); + + // Rather than insert into packetL[3], it is faster to initialize + // the otherwise empty packetH. + HH_ALIGNAS(16) uint64_t tmp[2] = {last4, 0}; + const V2x64U packetH(vld1q_u64(tmp)); + Update(packetH, packetL); + } + } + + HH_INLINE void Finalize(HHResult64* HH_RESTRICT result) { + // Mix together all lanes. + for (int n = 0; n < 4; n++) { + PermuteAndUpdate(); + } + + const V2x64U sum0 = v0L + mul0L; + const V2x64U sum1 = v1L + mul1L; + const V2x64U hash = sum0 + sum1; + vst1q_low_u64(reinterpret_cast(result), hash); + } + + HH_INLINE void Finalize(HHResult128* HH_RESTRICT result) { + for (int n = 0; n < 6; n++) { + PermuteAndUpdate(); + } + + const V2x64U sum0 = v0L + mul0L; + const V2x64U sum1 = v1H + mul1H; + const V2x64U hash = sum0 + sum1; + StoreUnaligned(hash, &(*result)[0]); + } + + HH_INLINE void Finalize(HHResult256* HH_RESTRICT result) { + for (int n = 0; n < 10; n++) { + PermuteAndUpdate(); + } + + const V2x64U sum0L = v0L + mul0L; + const V2x64U sum1L = v1L + mul1L; + const V2x64U sum0H = v0H + mul0H; + const V2x64U sum1H = v1H + mul1H; + const V2x64U hashL = ModularReduction(sum1L, sum0L); + const V2x64U hashH = ModularReduction(sum1H, sum0H); + StoreUnaligned(hashL, &(*result)[0]); + StoreUnaligned(hashH, &(*result)[2]); + } + + static HH_INLINE void ZeroInitialize(char* HH_RESTRICT buffer_bytes) { + for (size_t i = 0; i < sizeof(HHPacket); ++i) { + buffer_bytes[i] = 0; + } + } + + static HH_INLINE void CopyPartial(const char* HH_RESTRICT from, + const size_t size_mod32, + char* HH_RESTRICT buffer) { + for (size_t i = 0; i < size_mod32; ++i) { + buffer[i] = from[i]; + } + } + + static HH_INLINE void AppendPartial(const char* HH_RESTRICT from, + const size_t size_mod32, + char* HH_RESTRICT buffer, + const size_t buffer_valid) { + for (size_t i = 0; i < size_mod32; ++i) { + buffer[buffer_valid + i] = from[i]; + } + } + + HH_INLINE void AppendAndUpdate(const char* HH_RESTRICT from, + const size_t size_mod32, + const char* HH_RESTRICT buffer, + const size_t buffer_valid) { + HH_ALIGNAS(32) HHPacket tmp; + for (size_t i = 0; i < buffer_valid; ++i) { + tmp[i] = buffer[i]; + } + for (size_t i = 0; i < size_mod32; ++i) { + tmp[buffer_valid + i] = from[i]; + } + Update(tmp); + } + + private: + // Swap 32-bit halves of each lane (caller swaps 128-bit halves) + static HH_INLINE V2x64U Rotate64By32(const V2x64U& v) { + return V2x64U(vreinterpretq_u64_u32(vrev64q_u32(vreinterpretq_u32_u64(v)))); + } + + static HH_INLINE V2x64U ZipperMerge(const V2x64U& v) { + // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to + // varying degrees. In descending order of goodness, bytes + // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32. + // As expected, the upper and lower bytes are much worse. + // For each 64-bit lane, our objectives are: + // 1) maximizing and equalizing total goodness across each lane's bytes; + // 2) mixing with bytes from the neighboring lane; + // 3) placing the worst bytes in the upper 32 bits because those will not + // be used in the next 32x32 multiplication. + + // The positions of each byte in the new vector. + const uint8_t shuffle_positions[] = {3, 12, 2, 5, 14, 1, 15, 0, + 11, 4, 10, 13, 9, 6, 8, 7}; + const uint8x16_t tbl = vld1q_u8(shuffle_positions); + + // Note: vqtbl1q_u8 is polyfilled for ARMv7a in vector_neon.h. + return V2x64U( + vreinterpretq_u64_u8(vqtbl1q_u8(vreinterpretq_u8_u64(v), tbl))); + } + + HH_INLINE void Update(const V2x64U& packetH, const V2x64U& packetL) { + v1L += packetL; + v1H += packetH; + v1L += mul0L; + v1H += mul0H; + // mul0L ^= (v1L & 0xFFFFFFFF) * (v0L >> 32); + mul0L ^= V2x64U(vmull_u32(vmovn_u64(v1L), vshrn_n_u64(v0L, 32))); + // mul0H ^= (v1H & 0xFFFFFFFF) * (v0H >> 32); + mul0H ^= V2x64U(vmull_u32(vmovn_u64(v1H), vshrn_n_u64(v0H, 32))); + v0L += mul1L; + v0H += mul1H; + // mul1L ^= (v0L & 0xFFFFFFFF) * (v1L >> 32); + mul1L ^= V2x64U(vmull_u32(vmovn_u64(v0L), vshrn_n_u64(v1L, 32))); + // mul1H ^= (v0H & 0xFFFFFFFF) * (v1H >> 32); + mul1H ^= V2x64U(vmull_u32(vmovn_u64(v0H), vshrn_n_u64(v1H, 32))); + v0L += ZipperMerge(v1L); + v0H += ZipperMerge(v1H); + v1L += ZipperMerge(v0L); + v1H += ZipperMerge(v0H); + } + + HH_INLINE void PermuteAndUpdate() { + // It is slightly better to permute v0 than v1; it will be added to v1. + Update(Rotate64By32(v0L), Rotate64By32(v0H)); + } + + // Returns zero-initialized vector with the lower "size" = 0, 4, 8 or 12 + // bytes loaded from "bytes". Serves as a replacement for AVX2 maskload_epi32. + static HH_INLINE V2x64U LoadMultipleOfFour(const char* bytes, + const size_t size) { + const uint32_t* words = reinterpret_cast(bytes); + // Mask of 1-bits where the final 4 bytes should be inserted (replacement + // for variable shift/insert using broadcast+blend). + alignas(16) const uint64_t mask_pattern[2] = {0xFFFFFFFFULL, 0}; + V2x64U mask4(vld1q_u64(mask_pattern)); // 'insert' into lane 0 + V2x64U ret(vdupq_n_u64(0)); + if (size & 8) { + ret = V2x64U(vld1q_low_u64(reinterpret_cast(words))); + // mask4 = 0 ~0 0 0 ('insert' into lane 2) + mask4 = V2x64U(vshlq_n_u128(mask4, 8)); + words += 2; + } + // Final 4 (possibly after the 8 above); 'insert' into lane 0 or 2 of ret. + if (size & 4) { + // = 0 word2 0 word2; mask4 will select which lane to keep. + const V2x64U broadcast(vreinterpretq_u64_u32(vdupq_n_u32(words[0]))); + // (slightly faster than blendv_epi8) + ret |= V2x64U(broadcast & mask4); + } + return ret; + } + + // XORs x << 1 and x << 2 into *out after clearing the upper two bits of x. + // Bit shifts are only possible on independent 64-bit lanes. We therefore + // insert the upper bits of x[0] that were lost into x[1]. + // Thanks to D. Lemire for helpful comments! + static HH_INLINE void XorByShift128Left12(const V2x64U& x, + V2x64U* HH_RESTRICT out) { + const V4x32U zero(vdupq_n_u32(0)); + const V2x64U sign_bit128( + vreinterpretq_u64_u32(vsetq_lane_u32(0x80000000u, zero, 3))); + const V2x64U top_bits2 = x >> (64 - 2); + HH_COMPILER_FENCE; + const V2x64U shifted1_unmasked = x + x; // (avoids needing port0) + + // Only the lower half of top_bits1 will be used, so we + // can compute it before clearing the upper two bits of x. + const V2x64U top_bits1 = x >> (64 - 1); + const V2x64U shifted2 = shifted1_unmasked + shifted1_unmasked; + HH_COMPILER_FENCE; + + const V2x64U new_low_bits2(vshlq_n_u128(top_bits2, 8)); + *out ^= shifted2; + // The result must be as if the upper two bits of the input had been clear, + // otherwise we're no longer computing a reduction. + const V2x64U shifted1 = AndNot(sign_bit128, shifted1_unmasked); + HH_COMPILER_FENCE; + + const V2x64U new_low_bits1(vshlq_n_u128(top_bits1, 8)); + *out ^= new_low_bits2; + *out ^= shifted1; + *out ^= new_low_bits1; + } + + // Modular reduction by the irreducible polynomial (x^128 + x^2 + x). + // Input: a 256-bit number a3210. + static HH_INLINE V2x64U ModularReduction(const V2x64U& a32_unmasked, + const V2x64U& a10) { + // See Lemire, https://arxiv.org/pdf/1503.03465v8.pdf. + V2x64U out = a10; + XorByShift128Left12(a32_unmasked, &out); + return out; + } + + V2x64U v0L; + V2x64U v0H; + V2x64U v1L; + V2x64U v1H; + V2x64U mul0L; + V2x64U mul0H; + V2x64U mul1L; + V2x64U mul1H; +}; + +} // namespace HH_TARGET_NAME +} // namespace highwayhash + +#endif // HH_DISABLE_TARGET_SPECIFIC +#endif // HIGHWAYHASH_HH_NEON_H_ diff --git a/src/Native/libdero/include/highwayhash/hh_portable.cc b/src/Native/libdero/include/highwayhash/hh_portable.cc new file mode 100644 index 0000000000..f8c416dc68 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/hh_portable.cc @@ -0,0 +1,19 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +// WARNING: this is a "restricted" source file; avoid including any headers +// unless they are also restricted. See arch_specific.h for details. + +#define HH_TARGET_NAME Portable +#include "highwayhash_target.cc" diff --git a/src/Native/libdero/include/highwayhash/hh_portable.h b/src/Native/libdero/include/highwayhash/hh_portable.h new file mode 100644 index 0000000000..51f30423a0 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/hh_portable.h @@ -0,0 +1,302 @@ +// Copyright 2015-2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_HH_PORTABLE_H_ +#define HIGHWAYHASH_HH_PORTABLE_H_ + +// WARNING: this is a "restricted" header because it is included from +// translation units compiled with different flags. This header and its +// dependencies must not define any function unless it is static inline and/or +// within namespace HH_TARGET_NAME. See arch_specific.h for details. + +#include "arch_specific.h" +#include "compiler_specific.h" +#include "endianess.h" +#include "hh_types.h" +#include "load3.h" + +namespace highwayhash { +// See vector128.h for why this namespace is necessary; we match it here for +// consistency. As a result, this header requires textual inclusion. +namespace HH_TARGET_NAME { + +class HHStatePortable { + public: + static const int kNumLanes = 4; + using Lanes = uint64_t[kNumLanes]; + + explicit HH_INLINE HHStatePortable(const HHKey keys) { Reset(keys); } + + HH_INLINE void Reset(const HHKey keys) { + static const Lanes init0 = {0xdbe6d5d5fe4cce2full, 0xa4093822299f31d0ull, + 0x13198a2e03707344ull, 0x243f6a8885a308d3ull}; + static const Lanes init1 = {0x3bd39e10cb0ef593ull, 0xc0acf169b5f18a8cull, + 0xbe5466cf34e90c6cull, 0x452821e638d01377ull}; + Lanes rotated_keys; + Rotate64By32(keys, &rotated_keys); + Copy(init0, &mul0); + Copy(init1, &mul1); + Xor(init0, keys, &v0); + Xor(init1, rotated_keys, &v1); + } + + HH_INLINE void Update(const HHPacket& packet) { + Lanes packet_lanes; + CopyPartial(&packet[0], sizeof(HHPacket), + reinterpret_cast(&packet_lanes)); + for (int lane = 0; lane < kNumLanes; ++lane) { + packet_lanes[lane] = host_from_le64(packet_lanes[lane]); + } + Update(packet_lanes); + } + + HH_INLINE void UpdateRemainder(const char* bytes, const size_t size_mod32) { + // 'Length padding' differentiates zero-valued inputs that have the same + // size/32. mod32 is sufficient because each Update behaves as if a + // counter were injected, because the state is large and mixed thoroughly. + const uint64_t mod32_pair = + (static_cast(size_mod32) << 32) + size_mod32; + for (int lane = 0; lane < kNumLanes; ++lane) { + v0[lane] += mod32_pair; + } + Rotate32By(reinterpret_cast(&v1), size_mod32); + + const size_t size_mod4 = size_mod32 & 3; + const char* remainder = bytes + (size_mod32 & ~3); + + HH_ALIGNAS(32) HHPacket packet = {0}; + CopyPartial(bytes, remainder - bytes, &packet[0]); + + if (size_mod32 & 16) { // 16..31 bytes left + // Read the last 0..3 bytes and previous 1..4 into the upper bits. + // Insert into the upper four bytes of packet, which are zero. + uint32_t last4 = + Load3()(Load3::AllowReadBeforeAndReturn(), remainder, size_mod4); + last4 = host_from_le32(last4); + + CopyPartial(reinterpret_cast(&last4), 4, &packet[28]); + } else { // size_mod32 < 16 + uint64_t last4 = Load3()(Load3::AllowUnordered(), remainder, size_mod4); + last4 = host_from_le64(last4); + + // Rather than insert at packet + 28, it is faster to initialize + // the otherwise empty packet + 16 with up to 64 bits of padding. + CopyPartial(reinterpret_cast(&last4), sizeof(last4), + &packet[16]); + } + Update(packet); + } + + HH_INLINE void Finalize(HHResult64* HH_RESTRICT result) { + for (int n = 0; n < 4; n++) { + PermuteAndUpdate(); + } + + *result = v0[0] + v1[0] + mul0[0] + mul1[0]; + } + + HH_INLINE void Finalize(HHResult128* HH_RESTRICT result) { + for (int n = 0; n < 6; n++) { + PermuteAndUpdate(); + } + + (*result)[0] = v0[0] + mul0[0] + v1[2] + mul1[2]; + (*result)[1] = v0[1] + mul0[1] + v1[3] + mul1[3]; + } + + HH_INLINE void Finalize(HHResult256* HH_RESTRICT result) { + for (int n = 0; n < 10; n++) { + PermuteAndUpdate(); + } + + ModularReduction(v1[1] + mul1[1], v1[0] + mul1[0], v0[1] + mul0[1], + v0[0] + mul0[0], &(*result)[1], &(*result)[0]); + ModularReduction(v1[3] + mul1[3], v1[2] + mul1[2], v0[3] + mul0[3], + v0[2] + mul0[2], &(*result)[3], &(*result)[2]); + } + + static HH_INLINE void ZeroInitialize(char* HH_RESTRICT buffer) { + for (size_t i = 0; i < sizeof(HHPacket); ++i) { + buffer[i] = 0; + } + } + + static HH_INLINE void CopyPartial(const char* HH_RESTRICT from, + const size_t size_mod32, + char* HH_RESTRICT buffer) { + for (size_t i = 0; i < size_mod32; ++i) { + buffer[i] = from[i]; + } + } + + static HH_INLINE void AppendPartial(const char* HH_RESTRICT from, + const size_t size_mod32, + char* HH_RESTRICT buffer, + const size_t buffer_valid) { + for (size_t i = 0; i < size_mod32; ++i) { + buffer[buffer_valid + i] = from[i]; + } + } + + HH_INLINE void AppendAndUpdate(const char* HH_RESTRICT from, + const size_t size_mod32, + const char* HH_RESTRICT buffer, + const size_t buffer_valid) { + HH_ALIGNAS(32) HHPacket tmp; + for (size_t i = 0; i < buffer_valid; ++i) { + tmp[i] = buffer[i]; + } + for (size_t i = 0; i < size_mod32; ++i) { + tmp[buffer_valid + i] = from[i]; + } + Update(tmp); + } + + private: + static HH_INLINE void Copy(const Lanes& source, Lanes* HH_RESTRICT dest) { + for (int lane = 0; lane < kNumLanes; ++lane) { + (*dest)[lane] = source[lane]; + } + } + + static HH_INLINE void Add(const Lanes& source, Lanes* HH_RESTRICT dest) { + for (int lane = 0; lane < kNumLanes; ++lane) { + (*dest)[lane] += source[lane]; + } + } + + template + static HH_INLINE void Xor(const Lanes& op1, const LanesOrPointer& op2, + Lanes* HH_RESTRICT dest) { + for (int lane = 0; lane < kNumLanes; ++lane) { + (*dest)[lane] = op1[lane] ^ op2[lane]; + } + } + +// Clears all bits except one byte at the given offset. +#define MASK(v, bytes) ((v) & (0xFFull << ((bytes)*8))) + + // 16-byte permutation; shifting is about 10% faster than byte loads. + // Adds zipper-merge result to add*. + static HH_INLINE void ZipperMergeAndAdd(const uint64_t v1, const uint64_t v0, + uint64_t* HH_RESTRICT add1, + uint64_t* HH_RESTRICT add0) { + *add0 += ((MASK(v0, 3) + MASK(v1, 4)) >> 24) + + ((MASK(v0, 5) + MASK(v1, 6)) >> 16) + MASK(v0, 2) + + (MASK(v0, 1) << 32) + (MASK(v1, 7) >> 8) + (v0 << 56); + + *add1 += ((MASK(v1, 3) + MASK(v0, 4)) >> 24) + MASK(v1, 2) + + (MASK(v1, 5) >> 16) + (MASK(v1, 1) << 24) + (MASK(v0, 6) >> 8) + + (MASK(v1, 0) << 48) + MASK(v0, 7); + } + +#undef MASK + + // For inputs that are already in native byte order (e.g. PermuteAndAdd) + HH_INLINE void Update(const Lanes& packet_lanes) { + Add(packet_lanes, &v1); + Add(mul0, &v1); + + // (Loop is faster than unrolling) + for (int lane = 0; lane < kNumLanes; ++lane) { + const uint32_t v1_32 = static_cast(v1[lane]); + mul0[lane] ^= v1_32 * (v0[lane] >> 32); + v0[lane] += mul1[lane]; + const uint32_t v0_32 = static_cast(v0[lane]); + mul1[lane] ^= v0_32 * (v1[lane] >> 32); + } + + ZipperMergeAndAdd(v1[1], v1[0], &v0[1], &v0[0]); + ZipperMergeAndAdd(v1[3], v1[2], &v0[3], &v0[2]); + + ZipperMergeAndAdd(v0[1], v0[0], &v1[1], &v1[0]); + ZipperMergeAndAdd(v0[3], v0[2], &v1[3], &v1[2]); + } + + static HH_INLINE uint64_t Rotate64By32(const uint64_t x) { + return (x >> 32) | (x << 32); + } + + template + static HH_INLINE void Rotate64By32(const LanesOrPointer& v, + Lanes* HH_RESTRICT rotated) { + for (int i = 0; i < kNumLanes; ++i) { + (*rotated)[i] = Rotate64By32(v[i]); + } + } + + static HH_INLINE void Rotate32By(uint32_t* halves, const uint64_t count) { + for (int i = 0; i < 2 * kNumLanes; ++i) { + const uint32_t x = halves[i]; + halves[i] = (x << count) | (x >> (32 - count)); + } + } + + static HH_INLINE void Permute(const Lanes& v, Lanes* HH_RESTRICT permuted) { + (*permuted)[0] = Rotate64By32(v[2]); + (*permuted)[1] = Rotate64By32(v[3]); + (*permuted)[2] = Rotate64By32(v[0]); + (*permuted)[3] = Rotate64By32(v[1]); + } + + HH_INLINE void PermuteAndUpdate() { + Lanes permuted; + Permute(v0, &permuted); + Update(permuted); + } + + // Computes a << kBits for 128-bit a = (a1, a0). + // Bit shifts are only possible on independent 64-bit lanes. We therefore + // insert the upper bits of a0 that were lost into a1. This is slightly + // shorter than Lemire's (a << 1) | (((a >> 8) << 1) << 8) approach. + template + static HH_INLINE void Shift128Left(uint64_t* HH_RESTRICT a1, + uint64_t* HH_RESTRICT a0) { + const uint64_t shifted1 = (*a1) << kBits; + const uint64_t top_bits = (*a0) >> (64 - kBits); + *a0 <<= kBits; + *a1 = shifted1 | top_bits; + } + + // Modular reduction by the irreducible polynomial (x^128 + x^2 + x). + // Input: a 256-bit number a3210. + static HH_INLINE void ModularReduction(const uint64_t a3_unmasked, + const uint64_t a2, const uint64_t a1, + const uint64_t a0, + uint64_t* HH_RESTRICT m1, + uint64_t* HH_RESTRICT m0) { + // The upper two bits must be clear, otherwise a3 << 2 would lose bits, + // in which case we're no longer computing a reduction. + const uint64_t a3 = a3_unmasked & 0x3FFFFFFFFFFFFFFFull; + // See Lemire, https://arxiv.org/pdf/1503.03465v8.pdf. + uint64_t a3_shl1 = a3; + uint64_t a2_shl1 = a2; + uint64_t a3_shl2 = a3; + uint64_t a2_shl2 = a2; + Shift128Left<1>(&a3_shl1, &a2_shl1); + Shift128Left<2>(&a3_shl2, &a2_shl2); + *m1 = a1 ^ a3_shl1 ^ a3_shl2; + *m0 = a0 ^ a2_shl1 ^ a2_shl2; + } + + Lanes v0; + Lanes v1; + Lanes mul0; + Lanes mul1; +}; + +} // namespace HH_TARGET_NAME +} // namespace highwayhash + +#endif // HIGHWAYHASH_HH_PORTABLE_H_ diff --git a/src/Native/libdero/include/highwayhash/hh_sse41.cc b/src/Native/libdero/include/highwayhash/hh_sse41.cc new file mode 100644 index 0000000000..31c8ffd6ff --- /dev/null +++ b/src/Native/libdero/include/highwayhash/hh_sse41.cc @@ -0,0 +1,19 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +// WARNING: this is a "restricted" source file; avoid including any headers +// unless they are also restricted. See arch_specific.h for details. + +#define HH_TARGET_NAME SSE41 +#include "highwayhash_target.cc" diff --git a/src/Native/libdero/include/highwayhash/hh_sse41.h b/src/Native/libdero/include/highwayhash/hh_sse41.h new file mode 100644 index 0000000000..322947eafc --- /dev/null +++ b/src/Native/libdero/include/highwayhash/hh_sse41.h @@ -0,0 +1,327 @@ +// Copyright 2015-2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_HH_SSE41_H_ +#define HIGHWAYHASH_HH_SSE41_H_ + +// WARNING: this is a "restricted" header because it is included from +// translation units compiled with different flags. This header and its +// dependencies must not define any function unless it is static inline and/or +// within namespace HH_TARGET_NAME. See arch_specific.h for details. + +#include "arch_specific.h" +#include "compiler_specific.h" +#include "hh_buffer.h" +#include "hh_types.h" +#include "load3.h" +#include "vector128.h" + +// For auto-dependency generation, we need to include all headers but not their +// contents (otherwise compilation fails because -msse4.1 is not specified). +#ifndef HH_DISABLE_TARGET_SPECIFIC + +namespace highwayhash { +// See vector128.h for why this namespace is necessary; matching it here makes +// it easier use the vector128 symbols, but requires textual inclusion. +namespace HH_TARGET_NAME { + +// J-lanes tree hashing: see https://doi.org/10.4236/jis.2014.53010 +// Uses pairs of SSE4.1 instructions to emulate the AVX-2 algorithm. +class HHStateSSE41 { + public: + explicit HH_INLINE HHStateSSE41(const HHKey key) { Reset(key); } + + HH_INLINE void Reset(const HHKey key) { + // "Nothing up my sleeve numbers"; see HHStateTAVX2. + const V2x64U init0L(0xa4093822299f31d0ull, 0xdbe6d5d5fe4cce2full); + const V2x64U init0H(0x243f6a8885a308d3ull, 0x13198a2e03707344ull); + const V2x64U init1L(0xc0acf169b5f18a8cull, 0x3bd39e10cb0ef593ull); + const V2x64U init1H(0x452821e638d01377ull, 0xbe5466cf34e90c6cull); + const V2x64U keyL = LoadUnaligned(key + 0); + const V2x64U keyH = LoadUnaligned(key + 2); + v0L = keyL ^ init0L; + v0H = keyH ^ init0H; + v1L = Rotate64By32(keyL) ^ init1L; + v1H = Rotate64By32(keyH) ^ init1H; + mul0L = init0L; + mul0H = init0H; + mul1L = init1L; + mul1H = init1H; + } + + HH_INLINE void Update(const HHPacket& packet_bytes) { + const uint64_t* HH_RESTRICT packet = + reinterpret_cast(packet_bytes); + const V2x64U packetL = LoadUnaligned(packet + 0); + const V2x64U packetH = LoadUnaligned(packet + 2); + Update(packetH, packetL); + } + + HH_INLINE void UpdateRemainder(const char* bytes, const size_t size_mod32) { + // 'Length padding' differentiates zero-valued inputs that have the same + // size/32. mod32 is sufficient because each Update behaves as if a + // counter were injected, because the state is large and mixed thoroughly. + const V4x32U vsize_mod32(static_cast(size_mod32)); + // Equivalent to storing size_mod32 in packet. + v0L += V2x64U(vsize_mod32); + v0H += V2x64U(vsize_mod32); + // Boosts the avalanche effect of mod32. + Rotate32By(&v1H, &v1L, size_mod32); + + const size_t size_mod4 = size_mod32 & 3; + const char* HH_RESTRICT remainder = bytes + (size_mod32 & ~3); + + if (HH_UNLIKELY(size_mod32 & 16)) { // 16..31 bytes left + const V2x64U packetL = + LoadUnaligned(reinterpret_cast(bytes)); + + V2x64U packetH = LoadMultipleOfFour(bytes + 16, size_mod32); + + const uint32_t last4 = + Load3()(Load3::AllowReadBeforeAndReturn(), remainder, size_mod4); + + // The upper four bytes of packetH are zero, so insert there. + packetH = V2x64U(_mm_insert_epi32(packetH, last4, 3)); + Update(packetH, packetL); + } else { // size_mod32 < 16 + const V2x64U packetL = LoadMultipleOfFour(bytes, size_mod32); + + const uint64_t last4 = + Load3()(Load3::AllowUnordered(), remainder, size_mod4); + + // Rather than insert into packetL[3], it is faster to initialize + // the otherwise empty packetH. + const V2x64U packetH(_mm_cvtsi64_si128(last4)); + Update(packetH, packetL); + } + } + + HH_INLINE void Finalize(HHResult64* HH_RESTRICT result) { + // Mix together all lanes. + for (int n = 0; n < 4; n++) { + PermuteAndUpdate(); + } + + const V2x64U sum0 = v0L + mul0L; + const V2x64U sum1 = v1L + mul1L; + const V2x64U hash = sum0 + sum1; + _mm_storel_epi64(reinterpret_cast<__m128i*>(result), hash); + } + + HH_INLINE void Finalize(HHResult128* HH_RESTRICT result) { + for (int n = 0; n < 6; n++) { + PermuteAndUpdate(); + } + + const V2x64U sum0 = v0L + mul0L; + const V2x64U sum1 = v1H + mul1H; + const V2x64U hash = sum0 + sum1; + StoreUnaligned(hash, &(*result)[0]); + } + + HH_INLINE void Finalize(HHResult256* HH_RESTRICT result) { + for (int n = 0; n < 10; n++) { + PermuteAndUpdate(); + } + + const V2x64U sum0L = v0L + mul0L; + const V2x64U sum1L = v1L + mul1L; + const V2x64U sum0H = v0H + mul0H; + const V2x64U sum1H = v1H + mul1H; + const V2x64U hashL = ModularReduction(sum1L, sum0L); + const V2x64U hashH = ModularReduction(sum1H, sum0H); + StoreUnaligned(hashL, &(*result)[0]); + StoreUnaligned(hashH, &(*result)[2]); + } + + static HH_INLINE void ZeroInitialize(char* HH_RESTRICT buffer_bytes) { + __m128i* buffer = reinterpret_cast<__m128i*>(buffer_bytes); + const __m128i zero = _mm_setzero_si128(); + _mm_store_si128(buffer + 0, zero); + _mm_store_si128(buffer + 1, zero); + } + + static HH_INLINE void CopyPartial(const char* HH_RESTRICT from, + const size_t size_mod32, + char* HH_RESTRICT buffer) { + for (size_t i = 0; i < size_mod32; ++i) { + buffer[i] = from[i]; + } + } + + static HH_INLINE void AppendPartial(const char* HH_RESTRICT from, + const size_t size_mod32, + char* HH_RESTRICT buffer, + const size_t buffer_valid) { + for (size_t i = 0; i < size_mod32; ++i) { + buffer[buffer_valid + i] = from[i]; + } + } + + HH_INLINE void AppendAndUpdate(const char* HH_RESTRICT from, + const size_t size_mod32, + const char* HH_RESTRICT buffer, + const size_t buffer_valid) { + HH_ALIGNAS(32) HHPacket tmp; + for (size_t i = 0; i < buffer_valid; ++i) { + tmp[i] = buffer[i]; + } + for (size_t i = 0; i < size_mod32; ++i) { + tmp[buffer_valid + i] = from[i]; + } + Update(tmp); + } + + private: + // Swap 32-bit halves of each lane (caller swaps 128-bit halves) + static HH_INLINE V2x64U Rotate64By32(const V2x64U& v) { + return V2x64U(_mm_shuffle_epi32(v, _MM_SHUFFLE(2, 3, 0, 1))); + } + + // Rotates 32-bit lanes by "count" bits. + static HH_INLINE void Rotate32By(V2x64U* HH_RESTRICT vH, + V2x64U* HH_RESTRICT vL, + const uint64_t count) { + // WARNING: the shift count is 64 bits, so we can't reuse vsize_mod32, + // which is broadcast into 32-bit lanes. + const __m128i count_left = _mm_cvtsi64_si128(count); + const __m128i count_right = _mm_cvtsi64_si128(32 - count); + const V2x64U shifted_leftL(_mm_sll_epi32(*vL, count_left)); + const V2x64U shifted_leftH(_mm_sll_epi32(*vH, count_left)); + const V2x64U shifted_rightL(_mm_srl_epi32(*vL, count_right)); + const V2x64U shifted_rightH(_mm_srl_epi32(*vH, count_right)); + *vL = shifted_leftL | shifted_rightL; + *vH = shifted_leftH | shifted_rightH; + } + + static HH_INLINE V2x64U ZipperMerge(const V2x64U& v) { + // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to + // varying degrees. In descending order of goodness, bytes + // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32. + // As expected, the upper and lower bytes are much worse. + // For each 64-bit lane, our objectives are: + // 1) maximizing and equalizing total goodness across each lane's bytes; + // 2) mixing with bytes from the neighboring lane; + // 3) placing the worst bytes in the upper 32 bits because those will not + // be used in the next 32x32 multiplication. + const uint64_t hi = 0x070806090D0A040Bull; + const uint64_t lo = 0x000F010E05020C03ull; + return V2x64U(_mm_shuffle_epi8(v, V2x64U(hi, lo))); + } + + HH_INLINE void Update(const V2x64U& packetH, const V2x64U& packetL) { + v1L += packetL; + v1H += packetH; + v1L += mul0L; + v1H += mul0H; + mul0L ^= V2x64U(_mm_mul_epu32(v1L, Rotate64By32(v0L))); + mul0H ^= V2x64U(_mm_mul_epu32(v1H, v0H >> 32)); + v0L += mul1L; + v0H += mul1H; + mul1L ^= V2x64U(_mm_mul_epu32(v0L, Rotate64By32(v1L))); + mul1H ^= V2x64U(_mm_mul_epu32(v0H, v1H >> 32)); + v0L += ZipperMerge(v1L); + v0H += ZipperMerge(v1H); + v1L += ZipperMerge(v0L); + v1H += ZipperMerge(v0H); + } + + HH_INLINE void PermuteAndUpdate() { + // It is slightly better to permute v0 than v1; it will be added to v1. + // AVX-2 Permute also swaps 128-bit halves, so swap input operands. + Update(Rotate64By32(v0L), Rotate64By32(v0H)); + } + + // Returns zero-initialized vector with the lower "size" = 0, 4, 8 or 12 + // bytes loaded from "bytes". Serves as a replacement for AVX2 maskload_epi32. + static HH_INLINE V2x64U LoadMultipleOfFour(const char* bytes, + const size_t size) { + const uint32_t* words = reinterpret_cast(bytes); + // Mask of 1-bits where the final 4 bytes should be inserted (replacement + // for variable shift/insert using broadcast+blend). + V2x64U mask4(_mm_cvtsi64_si128(0xFFFFFFFFULL)); // 'insert' into lane 0 + V2x64U ret(0); + if (size & 8) { + ret = V2x64U(_mm_loadl_epi64(reinterpret_cast(words))); + // mask4 = 0 ~0 0 0 ('insert' into lane 2) + mask4 = V2x64U(_mm_slli_si128(mask4, 8)); + words += 2; + } + // Final 4 (possibly after the 8 above); 'insert' into lane 0 or 2 of ret. + if (size & 4) { + const __m128i word2 = _mm_cvtsi32_si128(words[0]); + // = 0 word2 0 word2; mask4 will select which lane to keep. + const V2x64U broadcast(_mm_shuffle_epi32(word2, 0x00)); + // (slightly faster than blendv_epi8) + ret |= V2x64U(broadcast & mask4); + } + return ret; + } + + // XORs x << 1 and x << 2 into *out after clearing the upper two bits of x. + // Bit shifts are only possible on independent 64-bit lanes. We therefore + // insert the upper bits of x[0] that were lost into x[1]. + // Thanks to D. Lemire for helpful comments! + static HH_INLINE void XorByShift128Left12(const V2x64U& x, + V2x64U* HH_RESTRICT out) { + const V2x64U zero(_mm_setzero_si128()); + const V2x64U sign_bit128(_mm_insert_epi32(zero, 0x80000000u, 3)); + const V2x64U top_bits2 = x >> (64 - 2); + HH_COMPILER_FENCE; + const V2x64U shifted1_unmasked = x + x; // (avoids needing port0) + + // Only the lower half of top_bits1 will be used, so we + // can compute it before clearing the upper two bits of x. + const V2x64U top_bits1 = x >> (64 - 1); + const V2x64U shifted2 = shifted1_unmasked + shifted1_unmasked; + HH_COMPILER_FENCE; + + const V2x64U new_low_bits2(_mm_slli_si128(top_bits2, 8)); + *out ^= shifted2; + // The result must be as if the upper two bits of the input had been clear, + // otherwise we're no longer computing a reduction. + const V2x64U shifted1 = AndNot(sign_bit128, shifted1_unmasked); + HH_COMPILER_FENCE; + + const V2x64U new_low_bits1(_mm_slli_si128(top_bits1, 8)); + *out ^= new_low_bits2; + *out ^= shifted1; + *out ^= new_low_bits1; + } + + // Modular reduction by the irreducible polynomial (x^128 + x^2 + x). + // Input: a 256-bit number a3210. + static HH_INLINE V2x64U ModularReduction(const V2x64U& a32_unmasked, + const V2x64U& a10) { + // See Lemire, https://arxiv.org/pdf/1503.03465v8.pdf. + V2x64U out = a10; + XorByShift128Left12(a32_unmasked, &out); + return out; + } + + V2x64U v0L; + V2x64U v0H; + V2x64U v1L; + V2x64U v1H; + V2x64U mul0L; + V2x64U mul0H; + V2x64U mul1L; + V2x64U mul1H; +}; + +} // namespace HH_TARGET_NAME +} // namespace highwayhash + +#endif // HH_DISABLE_TARGET_SPECIFIC +#endif // HIGHWAYHASH_HH_SSE41_H_ diff --git a/src/Native/libdero/include/highwayhash/hh_types.h b/src/Native/libdero/include/highwayhash/hh_types.h new file mode 100644 index 0000000000..f350d70f65 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/hh_types.h @@ -0,0 +1,50 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_HH_TYPES_H_ +#define HIGHWAYHASH_HH_TYPES_H_ + +// WARNING: included from c_bindings => must be C-compatible. +// WARNING: this is a "restricted" header because it is included from +// translation units compiled with different flags. This header and its +// dependencies must not define any function unless it is static inline and/or +// within namespace HH_TARGET_NAME. See arch_specific.h for details. + +#include // size_t +#include + +#ifdef __cplusplus +namespace highwayhash { +#endif + +// 256-bit secret key that should remain unknown to attackers. +// We recommend initializing it to a random value. +typedef uint64_t HHKey[4]; + +// How much input is hashed by one call to HHStateT::Update. +typedef char HHPacket[32]; + +// Hash 'return' types. +typedef uint64_t HHResult64; // returned directly +typedef uint64_t HHResult128[2]; +typedef uint64_t HHResult256[4]; + +// Called if a test fails, indicating which target and size. +typedef void (*HHNotify)(const char*, size_t); + +#ifdef __cplusplus +} // namespace highwayhash +#endif + +#endif // HIGHWAYHASH_HH_TYPES_H_ diff --git a/src/Native/libdero/include/highwayhash/hh_vsx.cc b/src/Native/libdero/include/highwayhash/hh_vsx.cc new file mode 100644 index 0000000000..41f797980b --- /dev/null +++ b/src/Native/libdero/include/highwayhash/hh_vsx.cc @@ -0,0 +1,22 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +// WARNING: this is a "restricted" source file; avoid including any headers +// unless they are also restricted. See arch_specific.h for details. + +#define HH_TARGET_NAME VSX + +#ifdef __VSX__ +#include "highwayhash_target.cc" +#endif diff --git a/src/Native/libdero/include/highwayhash/hh_vsx.h b/src/Native/libdero/include/highwayhash/hh_vsx.h new file mode 100644 index 0000000000..abb15020e5 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/hh_vsx.h @@ -0,0 +1,335 @@ +// Copyright 2015-2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_HH_VSX_H_ +#define HIGHWAYHASH_HH_VSX_H_ + +// WARNING: this is a "restricted" header because it is included from +// translation units compiled with different flags. This header and its +// dependencies must not define any function unless it is static inline and/or +// within namespace HH_TARGET_NAME. See arch_specific.h for details. + +#include "arch_specific.h" +#include "compiler_specific.h" +#include "hh_types.h" +#include "load3.h" + +// For auto-dependency generation, we need to include all headers but not their +// contents +#ifndef HH_DISABLE_TARGET_SPECIFIC + +#include +#undef vector +#undef pixel +#undef bool + +namespace highwayhash { + +typedef __vector unsigned long long PPC_VEC_U64; // NOLINT +typedef __vector unsigned int PPC_VEC_U32; +typedef __vector unsigned char PPC_VEC_U8; + +// See vector128.h for why this namespace is necessary; +namespace HH_TARGET_NAME { + +// Helper Functions + +// gcc doesn't support vec_mule() and vec_mulo() for vector long. +// Use the generic version, which is defined here only for gcc. + +#ifndef __clang__ +static HH_INLINE PPC_VEC_U64 vec_mule(PPC_VEC_U32 a, PPC_VEC_U32 b) { // NOLINT + PPC_VEC_U64 result; // NOLINT +#ifdef __LITTLE_ENDIAN__ + asm("vmulouw %0, %1, %2" : "=v"(result) : "v"(a), "v"(b)); +#else + asm("vmuleuw %0, %1, %2" : "=v"(result) : "v"(a), "v"(b)); +#endif + return result; +} +#endif + +// LoadUnaligned uses vec_vsx_ld(offset, address) format, +// Offset here is number of bytes and is 0 for this implementation. +static HH_INLINE PPC_VEC_U64 +LoadUnaligned(const uint64_t* const HH_RESTRICT from) { + const PPC_VEC_U64* const HH_RESTRICT p = + reinterpret_cast(from); + return vec_vsx_ld(0, p); +} + +static HH_INLINE void StoreUnaligned(const PPC_VEC_U64& hash, + uint64_t* const HH_RESTRICT to) { + PPC_VEC_U64* HH_RESTRICT p = reinterpret_cast(to); + vec_vsx_st(hash, 0, p); +} + +static HH_INLINE PPC_VEC_U64 MultiplyVectors(const PPC_VEC_U64& vec1, + const PPC_VEC_U64& vec2) { + return vec_mule(reinterpret_cast(vec1), + reinterpret_cast(vec2)); +} + +// J-lanes tree hashing: see https://doi.org/10.4236/jis.2014.53010 +class HHStateVSX { + public: + explicit HH_INLINE HHStateVSX(const HHKey key) { Reset(key); } + + HH_INLINE void Reset(const HHKey key) { + // "Nothing up my sleeve numbers"; + const PPC_VEC_U64 init0L = {0xdbe6d5d5fe4cce2full, 0xa4093822299f31d0ull}; + const PPC_VEC_U64 init0H = {0x13198a2e03707344ull, 0x243f6a8885a308d3ull}; + const PPC_VEC_U64 init1L = {0x3bd39e10cb0ef593ull, 0xc0acf169b5f18a8cull}; + const PPC_VEC_U64 init1H = {0xbe5466cf34e90c6cull, 0x452821e638d01377ull}; + const PPC_VEC_U64 keyL = LoadUnaligned(key); + const PPC_VEC_U64 keyH = LoadUnaligned(key + 2); + v0L = keyL ^ init0L; + v0H = keyH ^ init0H; + v1L = Rotate64By32(keyL) ^ init1L; + v1H = Rotate64By32(keyH) ^ init1H; + mul0L = init0L; + mul0H = init0H; + mul1L = init1L; + mul1H = init1H; + } + + HH_INLINE void Update(const HHPacket& packet_bytes) { + const uint64_t* HH_RESTRICT packet = + reinterpret_cast(packet_bytes); + const PPC_VEC_U64 packetL = LoadUnaligned(packet); + const PPC_VEC_U64 packetH = LoadUnaligned(packet + 2); + Update(packetH, packetL); + } + + HH_INLINE void UpdateRemainder(const char* bytes, const size_t size_mod32) { + // 'Length padding' differentiates zero-valued inputs that have the same + // size/32. mod32 is sufficient because each Update behaves as if a + // counter were injected, because the state is large and mixed thoroughly. + uint32_t size_rounded = static_cast(size_mod32); + PPC_VEC_U32 vsize_mod32 = {size_rounded, size_rounded, size_rounded, + size_rounded}; + // Equivalent to storing size_mod32 in packet. + v0L += reinterpret_cast(vsize_mod32); + v0H += reinterpret_cast(vsize_mod32); + + // Boosts the avalanche effect of mod32. + Rotate32By(&v1H, &v1L, size_mod32); + + const size_t size_mod4 = size_mod32 & 3; + const char* HH_RESTRICT remainder = bytes + (size_mod32 & ~3); + + if (HH_UNLIKELY(size_mod32 & 16)) { // 16..31 bytes left + const PPC_VEC_U64 packetL = + vec_vsx_ld(0, reinterpret_cast(bytes)); + + PPC_VEC_U64 packetH = LoadMultipleOfFour(bytes + 16, size_mod32); + + const uint32_t last4 = + Load3()(Load3::AllowReadBeforeAndReturn(), remainder, size_mod4); + + // The upper four bytes of packetH are zero, so insert there. + PPC_VEC_U32 packetH_32 = reinterpret_cast(packetH); + packetH_32[3] = last4; + packetH = reinterpret_cast(packetH_32); + Update(packetH, packetL); + } else { // size_mod32 < 16 + const PPC_VEC_U64 packetL = LoadMultipleOfFour(bytes, size_mod32); + + const uint64_t last4 = + Load3()(Load3::AllowUnordered(), remainder, size_mod4); + + // Rather than insert into packetL[3], it is faster to initialize + // the otherwise empty packetH. + const PPC_VEC_U64 packetH = {last4, 0}; + Update(packetH, packetL); + } + } + + HH_INLINE void Finalize(HHResult64* HH_RESTRICT result) { + // Mix together all lanes. + for (int n = 0; n < 4; n++) { + PermuteAndUpdate(); + } + const PPC_VEC_U64 hash = v0L + v1L + mul0L + mul1L; + *result = hash[0]; + } + + HH_INLINE void Finalize(HHResult128* HH_RESTRICT result) { + for (int n = 0; n < 6; n++) { + PermuteAndUpdate(); + } + const PPC_VEC_U64 hash = v0L + mul0L + v1H + mul1H; + StoreUnaligned(hash, *result); + } + + HH_INLINE void Finalize(HHResult256* HH_RESTRICT result) { + for (int n = 0; n < 10; n++) { + PermuteAndUpdate(); + } + const PPC_VEC_U64 sum0L = v0L + mul0L; + const PPC_VEC_U64 sum1L = v1L + mul1L; + const PPC_VEC_U64 sum0H = v0H + mul0H; + const PPC_VEC_U64 sum1H = v1H + mul1H; + const PPC_VEC_U64 hashL = ModularReduction(sum1L, sum0L); + const PPC_VEC_U64 hashH = ModularReduction(sum1H, sum0H); + StoreUnaligned(hashL, *result); + StoreUnaligned(hashH, *result + 2); + } + + static HH_INLINE void ZeroInitialize(char* HH_RESTRICT buffer_bytes) { + for (size_t i = 0; i < sizeof(HHPacket); ++i) { + buffer_bytes[i] = 0; + } + } + + static HH_INLINE void CopyPartial(const char* HH_RESTRICT from, + const size_t size_mod32, + char* HH_RESTRICT buffer) { + for (size_t i = 0; i < size_mod32; ++i) { + buffer[i] = from[i]; + } + } + + static HH_INLINE void AppendPartial(const char* HH_RESTRICT from, + const size_t size_mod32, + char* HH_RESTRICT buffer, + const size_t buffer_valid) { + for (size_t i = 0; i < size_mod32; ++i) { + buffer[buffer_valid + i] = from[i]; + } + } + + HH_INLINE void AppendAndUpdate(const char* HH_RESTRICT from, + const size_t size_mod32, + const char* HH_RESTRICT buffer, + const size_t buffer_valid) { + HH_ALIGNAS(32) HHPacket tmp; + for (size_t i = 0; i < buffer_valid; ++i) { + tmp[i] = buffer[i]; + } + for (size_t i = 0; i < size_mod32; ++i) { + tmp[buffer_valid + i] = from[i]; + } + Update(tmp); + } + + private: + // Swap 32-bit halves of each lane (caller swaps 128-bit halves) + static HH_INLINE PPC_VEC_U64 Rotate64By32(const PPC_VEC_U64& v) { + PPC_VEC_U64 shuffle_vec = {32, 32}; + return vec_rl(v, shuffle_vec); + } + + // Rotates 32-bit lanes by "count" bits. + static HH_INLINE void Rotate32By(PPC_VEC_U64* HH_RESTRICT vH, + PPC_VEC_U64* HH_RESTRICT vL, + const uint64_t count) { + // WARNING: the shift count is 64 bits, so we can't reuse vsize_mod32, + // which is broadcast into 32-bit lanes. + uint32_t count_rl = uint32_t(count); + PPC_VEC_U32 rot_left = {count_rl, count_rl, count_rl, count_rl}; + *vL = reinterpret_cast(vec_rl(PPC_VEC_U32(*vL), rot_left)); + *vH = reinterpret_cast(vec_rl(PPC_VEC_U32(*vH), rot_left)); + } + + static HH_INLINE PPC_VEC_U64 ZipperMerge(const PPC_VEC_U64& v) { + // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to + // varying degrees. In descending order of goodness, bytes + // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32. + // As expected, the upper and lower bytes are much worse. + // For each 64-bit lane, our objectives are: + // 1) maximizing and equalizing total goodness across each lane's bytes; + // 2) mixing with bytes from the neighboring lane; + // 3) placing the worst bytes in the upper 32 bits because those will not + // be used in the next 32x32 multiplication. + + const PPC_VEC_U64 mask = {0x000F010E05020C03ull, 0x070806090D0A040Bull}; + return vec_vperm(v, v, reinterpret_cast(mask)); + } + + HH_INLINE void Update(const PPC_VEC_U64& packetH, + const PPC_VEC_U64& packetL) { + // Tried rearranging the instructions below and benchmarks are similar + v1L += packetL + mul0L; + v1H += packetH + mul0H; + mul0L ^= MultiplyVectors(v1L, Rotate64By32(v0L)); + mul0H ^= MultiplyVectors(v1H, v0H >> 32); + v0L += mul1L; + v0H += mul1H; + mul1L ^= MultiplyVectors(v0L, Rotate64By32(v1L)); + mul1H ^= MultiplyVectors(v0H, v1H >> 32); + v0L += ZipperMerge(v1L); + v1L += ZipperMerge(v0L); + v0H += ZipperMerge(v1H); + v1H += ZipperMerge(v0H); + } + + HH_INLINE void PermuteAndUpdate() { + // Permutes v0L and V0H by swapping 32 bits halves of each lane + Update(Rotate64By32(v0L), Rotate64By32(v0H)); + } + + // Returns zero-initialized vector with the lower "size" = 0, 4, 8 or 12 + // bytes loaded from "bytes". Serves as a replacement for AVX2 maskload_epi32. + static HH_INLINE PPC_VEC_U64 LoadMultipleOfFour(const char* bytes, + const size_t size) { + const uint32_t* words = reinterpret_cast(bytes); + // Updating the entries, as if done by vec_insert function call + PPC_VEC_U32 ret = {0, 0, 0, 0}; + if (size & 8) { + ret[0] = words[0]; + ret[1] = words[1]; + words += 2; + if (size & 4) { + ret[2] = words[0]; + } + } else if (size & 4) { + ret[0] = words[0]; + } + return reinterpret_cast(ret); + } + + // Modular reduction by the irreducible polynomial (x^128 + x^2 + x). + // Input: a 256-bit number a3210. + static HH_INLINE PPC_VEC_U64 ModularReduction(const PPC_VEC_U64& a32_unmasked, + const PPC_VEC_U64& a10) { + // See Lemire, https://arxiv.org/pdf/1503.03465v8.pdf. + PPC_VEC_U64 out = a10; + const PPC_VEC_U64 shifted1 = reinterpret_cast( + vec_sll(reinterpret_cast(a32_unmasked), vec_splat_u8(1))); + const PPC_VEC_U64 shifted2 = reinterpret_cast( + vec_sll(reinterpret_cast(a32_unmasked), vec_splat_u8(2))); + // The result must be as if the upper two bits of the input had been clear, + // otherwise we're no longer computing a reduction. + const PPC_VEC_U64 mask = {0xFFFFFFFFFFFFFFFFull, 0x7FFFFFFFFFFFFFFFull}; + const PPC_VEC_U64 shifted1_masked = shifted1 & mask; + out ^= shifted1_masked ^ shifted2; + return out; + } + + PPC_VEC_U64 v0L; + PPC_VEC_U64 v0H; + PPC_VEC_U64 v1L; + PPC_VEC_U64 v1H; + PPC_VEC_U64 mul0L; + PPC_VEC_U64 mul0H; + PPC_VEC_U64 mul1L; + PPC_VEC_U64 mul1H; +}; + +} // namespace HH_TARGET_NAME +} // namespace highwayhash + +#endif // HH_DISABLE_TARGET_SPECIFIC +#endif // HIGHWAYHASH_HH_VSX_H_ diff --git a/src/Native/libdero/include/highwayhash/highwayhash.h b/src/Native/libdero/include/highwayhash/highwayhash.h new file mode 100644 index 0000000000..bc5010c467 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/highwayhash.h @@ -0,0 +1,216 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_HIGHWAYHASH_H_ +#define HIGHWAYHASH_HIGHWAYHASH_H_ + +// This header's templates are useful for inlining into other CPU-specific code: +// template CodeUsingHash() { HighwayHashT(...); }, +// and can also be instantiated with HH_TARGET when callers don't care about the +// exact implementation. Otherwise, they are implementation details of the +// highwayhash_target wrapper. Use that instead if you need to detect the best +// available implementation at runtime. + +// WARNING: this is a "restricted" header because it is included from +// translation units compiled with different flags. This header and its +// dependencies must not define any function unless it is static inline and/or +// within namespace HH_TARGET_NAME. See arch_specific.h for details. + +#include "arch_specific.h" +#include "compiler_specific.h" +#include "hh_types.h" + +#if HH_ARCH_X64 +#include "iaca.h" +#endif + +// Include exactly one (see arch_specific.h) header, which defines a state +// object in a target-specific namespace, e.g. AVX2::HHStateAVX2. +// Attempts to use "computed includes" (#define MACRO "path/or_just_filename", +// #include MACRO) fail with 'file not found', so we need an #if chain. +#if HH_TARGET == HH_TARGET_AVX2 +#include "hh_avx2.h" +#elif HH_TARGET == HH_TARGET_SSE41 +#include "hh_sse41.h" +#elif HH_TARGET == HH_TARGET_VSX +#include "hh_vsx.h" +#elif HH_TARGET == HH_TARGET_NEON +#include "hh_neon.h" +#elif HH_TARGET == HH_TARGET_Portable +#include "hh_portable.h" +#else +#error "Unknown target, add its hh_*.h include here." +#endif + +#ifndef HH_DISABLE_TARGET_SPECIFIC +namespace highwayhash { + +// Alias templates (HHStateT) cannot be specialized, so we need a helper struct. +// Note that hh_*.h don't just specialize HHStateT directly because vector128.h +// must reside in a distinct namespace (to allow including it from multiple +// translation units), and it is easier if its users, i.e. the concrete HHState, +// also reside in that same namespace, which precludes specialization. +template +struct HHStateForTarget {}; + +template <> +struct HHStateForTarget { + // (The namespace is sufficient and the additional HH_TARGET_NAME suffix is + // technically redundant, but it makes searching easier.) + using type = HH_TARGET_NAME::HH_ADD_TARGET_SUFFIX(HHState); +}; + +// Typically used as HHStateT. It would be easier to just have a +// concrete type HH_STATE, but this alias template is required by the +// templates in highwayhash_target.cc. +template +using HHStateT = typename HHStateForTarget::type; + +// Computes HighwayHash of "bytes" using the implementation chosen by "State". +// +// "state" is a HHStateT<> initialized with a key. +// "bytes" is the data to hash (possibly unaligned). +// "size" is the number of bytes to hash; we do not read any additional bytes. +// "hash" is a HHResult* (either 64, 128 or 256 bits). +// +// HighwayHash is a strong pseudorandom function with security claims +// [https://arxiv.org/abs/1612.06257]. It is intended as a safer general-purpose +// hash, about 4x faster than SipHash and 10x faster than BLAKE2. +// +// This template allows callers (e.g. tests) to invoke a specific +// implementation. It must be compiled with the flags required by the desired +// implementation. If the entire program cannot be built with these flags, use +// the wrapper in highwayhash_target.h instead. +// +// Callers wanting to hash multiple pieces of data should duplicate this +// function, calling HHStateT::Update for each input and only Finalizing once. +template +HH_INLINE void HighwayHashT(State* HH_RESTRICT state, + const char* HH_RESTRICT bytes, const size_t size, + Result* HH_RESTRICT hash) { + // BeginIACA(); + const size_t remainder = size & (sizeof(HHPacket) - 1); + const size_t truncated = size & ~(sizeof(HHPacket) - 1); + for (size_t offset = 0; offset < truncated; offset += sizeof(HHPacket)) { + state->Update(*reinterpret_cast(bytes + offset)); + } + + if (remainder != 0) { + state->UpdateRemainder(bytes + truncated, remainder); + } + + state->Finalize(hash); + // EndIACA(); +} + +// Wrapper class for incrementally hashing a series of data ranges. The final +// result is the same as HighwayHashT of the concatenation of all the ranges. +// This is useful for computing the hash of cords, iovecs, and similar +// data structures. +template +class HighwayHashCatT { + public: + HH_INLINE HighwayHashCatT(const HHKey& key) : state_(key) { + // Avoids msan uninitialized-memory warnings. + HHStateT::ZeroInitialize(buffer_); + } + + // Resets the state of the hasher so it can be used to hash a new string. + HH_INLINE void Reset(const HHKey& key) { + state_.Reset(key); + buffer_usage_ = 0; + } + + // Adds "bytes" to the internal buffer, feeding it to HHStateT::Update as + // required. Call this as often as desired. Only reads bytes within the + // interval [bytes, bytes + num_bytes). "num_bytes" == 0 has no effect. + // + // Beware that this implies hashing two strings {"A", ""} has the same result + // as {"", "A"}. To prevent this when hashing independent fields, you can + // append some extra (non-empty) data when a field is empty, or + // unconditionally also Append the field length. Either option would ensure + // the two examples above result in a different hash. + // + // There are no alignment requirements. + HH_INLINE void Append(const char* HH_RESTRICT bytes, size_t num_bytes) { + // BeginIACA(); + const size_t capacity = sizeof(HHPacket) - buffer_usage_; + // New bytes fit within buffer, but still not enough to Update. + if (HH_UNLIKELY(num_bytes < capacity)) { + HHStateT::AppendPartial(bytes, num_bytes, buffer_, buffer_usage_); + buffer_usage_ += num_bytes; + return; + } + + // HACK: ensures the state is kept in SIMD registers; otherwise, Update + // constantly load/stores its operands, which is much slower. + // Restrict-qualified pointers to external state or the state_ member are + // not sufficient for keeping this in registers. + HHStateT state_copy = state_; + + // Have prior bytes to flush. + const size_t buffer_usage = buffer_usage_; + if (HH_LIKELY(buffer_usage != 0)) { + // Calls update with prior buffer contents plus new data. Does not modify + // the buffer because some implementations can load into SIMD registers + // and Append to them directly. + state_copy.AppendAndUpdate(bytes, capacity, buffer_, buffer_usage); + bytes += capacity; + num_bytes -= capacity; + } + + // Buffer currently empty => Update directly from the source. + while (num_bytes >= sizeof(HHPacket)) { + state_copy.Update(*reinterpret_cast(bytes)); + bytes += sizeof(HHPacket); + num_bytes -= sizeof(HHPacket); + } + + // Unconditionally assign even if zero because we didn't reset to zero + // after the AppendAndUpdate above. + buffer_usage_ = num_bytes; + + state_ = state_copy; + + // Store any remainders in buffer, no-op if multiple of a packet. + if (HH_LIKELY(num_bytes != 0)) { + HHStateT::CopyPartial(bytes, num_bytes, buffer_); + } + // EndIACA(); + } + + // Stores the resulting 64, 128 or 256-bit hash of data previously passed to + // Append since construction or a prior call to Reset. + template // HHResult* + HH_INLINE void Finalize(Result* HH_RESTRICT hash) const { + // BeginIACA(); + HHStateT state_copy = state_; + const size_t buffer_usage = buffer_usage_; + if (HH_LIKELY(buffer_usage != 0)) { + state_copy.UpdateRemainder(buffer_, buffer_usage); + } + state_copy.Finalize(hash); + // EndIACA(); + } + + private: + HH_ALIGNAS(64) HHPacket buffer_; + HH_ALIGNAS(32) HHStateT state_; + // How many bytes in buffer_ (starting with offset 0) are valid. + size_t buffer_usage_ = 0; +}; + +} // namespace highwayhash +#endif // HH_DISABLE_TARGET_SPECIFIC +#endif // HIGHWAYHASH_HIGHWAYHASH_H_ diff --git a/src/Native/libdero/include/highwayhash/highwayhash_fuzzer.cc b/src/Native/libdero/include/highwayhash/highwayhash_fuzzer.cc new file mode 100644 index 0000000000..c75fcaf1c1 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/highwayhash_fuzzer.cc @@ -0,0 +1,25 @@ +#include "highwayhash_target.h" +#include "instruction_sets.h" + +using highwayhash::HHKey; +using highwayhash::HHResult64; +using highwayhash::HighwayHash; +using highwayhash::InstructionSets; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size < sizeof(uint64_t) * 4) { + return 0; + } + + // Generate the key. + const uint64_t *u64s = reinterpret_cast(data); + HH_ALIGNAS(32) const HHKey key = {u64s[0], u64s[1], u64s[2], u64s[3]}; + data += sizeof(uint64_t) * 4; + size -= sizeof(uint64_t) * 4; + + // Compute the hash. + HHResult64 result; + InstructionSets::Run(key, reinterpret_cast(data), + size, &result); + return 0; +} diff --git a/src/Native/libdero/include/highwayhash/highwayhash_target.cc b/src/Native/libdero/include/highwayhash/highwayhash_target.cc new file mode 100644 index 0000000000..b7f1777fd5 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/highwayhash_target.cc @@ -0,0 +1,104 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +// WARNING: this is a "restricted" source file; avoid including any headers +// unless they are also restricted. See arch_specific.h for details. + +#include "highwayhash_target.h" + +#include "highwayhash.h" + +#ifndef HH_DISABLE_TARGET_SPECIFIC +namespace highwayhash { + +extern "C" { +uint64_t HH_ADD_TARGET_SUFFIX(HighwayHash64_)(const HHKey key, + const char* bytes, + const uint64_t size) { + HHStateT state(key); + HHResult64 result; + HighwayHashT(&state, bytes, size, &result); + return result; +} +} // extern "C" + +template +void HighwayHash::operator()(const HHKey& key, + const char* HH_RESTRICT bytes, + const size_t size, + HHResult64* HH_RESTRICT hash) const { + HHStateT state(key); + HighwayHashT(&state, bytes, size, hash); +} + +template +void HighwayHash::operator()(const HHKey& key, + const char* HH_RESTRICT bytes, + const size_t size, + HHResult128* HH_RESTRICT hash) const { + HHStateT state(key); + HighwayHashT(&state, bytes, size, hash); +} + +template +void HighwayHash::operator()(const HHKey& key, + const char* HH_RESTRICT bytes, + const size_t size, + HHResult256* HH_RESTRICT hash) const { + HHStateT state(key); + HighwayHashT(&state, bytes, size, hash); +} + +template +void HighwayHashCat::operator()(const HHKey& key, + const StringView* HH_RESTRICT fragments, + const size_t num_fragments, + HHResult64* HH_RESTRICT hash) const { + HighwayHashCatT cat(key); + for (size_t i = 0; i < num_fragments; ++i) { + cat.Append(fragments[i].data, fragments[i].num_bytes); + } + cat.Finalize(hash); +} + +template +void HighwayHashCat::operator()(const HHKey& key, + const StringView* HH_RESTRICT fragments, + const size_t num_fragments, + HHResult128* HH_RESTRICT hash) const { + HighwayHashCatT cat(key); + for (size_t i = 0; i < num_fragments; ++i) { + cat.Append(fragments[i].data, fragments[i].num_bytes); + } + cat.Finalize(hash); +} + +template +void HighwayHashCat::operator()(const HHKey& key, + const StringView* HH_RESTRICT fragments, + const size_t num_fragments, + HHResult256* HH_RESTRICT hash) const { + HighwayHashCatT cat(key); + for (size_t i = 0; i < num_fragments; ++i) { + cat.Append(fragments[i].data, fragments[i].num_bytes); + } + cat.Finalize(hash); +} + +// Instantiate for the current target. +template struct HighwayHash; +template struct HighwayHashCat; + +} // namespace highwayhash +#endif // HH_DISABLE_TARGET_SPECIFIC diff --git a/src/Native/libdero/include/highwayhash/highwayhash_target.h b/src/Native/libdero/include/highwayhash/highwayhash_target.h new file mode 100644 index 0000000000..2f435f146d --- /dev/null +++ b/src/Native/libdero/include/highwayhash/highwayhash_target.h @@ -0,0 +1,91 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_HIGHWAYHASH_TARGET_H_ +#define HIGHWAYHASH_HIGHWAYHASH_TARGET_H_ + +// Adapter for the InstructionSets::Run dispatcher, which invokes the best +// implementations available on the current CPU. + +// WARNING: this is a "restricted" header because it is included from +// translation units compiled with different flags. This header and its +// dependencies must not define any function unless it is static inline and/or +// within namespace HH_TARGET_NAME. See arch_specific.h for details. + +#include "arch_specific.h" +#include "compiler_specific.h" +#include "hh_types.h" + +namespace highwayhash { + +// Usage: InstructionSets::Run(key, bytes, size, hash). +// This incurs some small dispatch overhead. If the entire program is compiled +// for the target CPU, you can instead call HighwayHashT directly to avoid any +// overhead. This template is instantiated in the source file, which is +// compiled once for every target with the required flags (e.g. -mavx2). +template +struct HighwayHash { + // Stores a 64/128/256 bit hash of "bytes" using the HighwayHashT + // implementation for the "Target" CPU. The hash result is identical + // regardless of which implementation is used. + // + // "key" is a (randomly generated or hard-coded) HHKey. + // "bytes" is the data to hash (possibly unaligned). + // "size" is the number of bytes to hash; we do not read any additional bytes. + // "hash" is a HHResult* (either 64, 128 or 256 bits). + // + // HighwayHash is a strong pseudorandom function with security claims + // [https://arxiv.org/abs/1612.06257]. It is intended as a safer + // general-purpose hash, 5x faster than SipHash and 10x faster than BLAKE2. + void operator()(const HHKey& key, const char* HH_RESTRICT bytes, + const size_t size, HHResult64* HH_RESTRICT hash) const; + void operator()(const HHKey& key, const char* HH_RESTRICT bytes, + const size_t size, HHResult128* HH_RESTRICT hash) const; + void operator()(const HHKey& key, const char* HH_RESTRICT bytes, + const size_t size, HHResult256* HH_RESTRICT hash) const; +}; + +// Replacement for C++17 std::string_view that avoids dependencies. +// A struct requires fewer allocations when calling HighwayHashCat with +// non-const "num_fragments". +struct StringView { + const char* data; // not necessarily aligned/padded + size_t num_bytes; // possibly zero +}; + +// Note: this interface avoids dispatch overhead per fragment. +template +struct HighwayHashCat { + // Stores a 64/128/256 bit hash of all "num_fragments" "fragments" using the + // HighwayHashCatT implementation for "Target". The hash result is identical + // to HighwayHash of the flattened data, regardless of Target. + // + // "key" is a (randomly generated or hard-coded) HHKey. + // "fragments" contain unaligned pointers and the number of valid bytes. + // "num_fragments" indicates the number of entries in "fragments". + // "hash" is a HHResult* (either 64, 128 or 256 bits). + void operator()(const HHKey& key, const StringView* HH_RESTRICT fragments, + const size_t num_fragments, + HHResult64* HH_RESTRICT hash) const; + void operator()(const HHKey& key, const StringView* HH_RESTRICT fragments, + const size_t num_fragments, + HHResult128* HH_RESTRICT hash) const; + void operator()(const HHKey& key, const StringView* HH_RESTRICT fragments, + const size_t num_fragments, + HHResult256* HH_RESTRICT hash) const; +}; + +} // namespace highwayhash + +#endif // HIGHWAYHASH_HIGHWAYHASH_TARGET_H_ diff --git a/src/Native/libdero/include/highwayhash/highwayhash_test.cc b/src/Native/libdero/include/highwayhash/highwayhash_test.cc new file mode 100644 index 0000000000..3d22c84a22 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/highwayhash_test.cc @@ -0,0 +1,391 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +// Ensures each implementation of HighwayHash returns consistent and unchanging +// hash values. + +#include "highwayhash_test_target.h" + +#include +#include +#include +#include + +#ifdef HH_GOOGLETEST +#include "testing/base/public/gunit.h" +#endif + +#include "data_parallel.h" +#include "highwayhash_target.h" +#include "instruction_sets.h" + +// Define to nonzero in order to print the (new) golden outputs. +// WARNING: HighwayHash is frozen, so the golden values must not change. +#define PRINT_RESULTS 0 + +namespace highwayhash { +namespace { + +// Known-good outputs are verified for all lengths in [0, 64]. +const size_t kMaxSize = 64; + +#if PRINT_RESULTS +void Print(const HHResult64 result) { printf("0x%016lXull,\n", result); } + +// For HHResult128/256. +template +void Print(const HHResult64 (&result)[kNumLanes]) { + printf("{ "); + for (int i = 0; i < kNumLanes; ++i) { + if (i != 0) { + printf(", "); + } + printf("0x%016lXull", result[i]); + } + printf("},\n"); +} +#endif // PRINT_RESULTS + +// Called when any test fails; exits immediately because one mismatch usually +// implies many others. +void OnFailure(const char* target_name, const size_t size) { + printf("Mismatch at size %zu for target %s\n", size, target_name); +#ifdef HH_GOOGLETEST + EXPECT_TRUE(false); +#endif + exit(1); +} + +// Verifies every combination of implementation and input size. Returns which +// targets were run/verified. +template +TargetBits VerifyImplementations(const Result (&known_good)[kMaxSize + 1]) { + const HHKey key = {0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL, + 0x1716151413121110ULL, 0x1F1E1D1C1B1A1918ULL}; + + TargetBits targets = ~0U; + + // For each test input: empty string, 00, 00 01, ... + char in[kMaxSize + 1] = {0}; + // Fast enough that we don't need a thread pool. + for (uint64_t size = 0; size <= kMaxSize; ++size) { + in[size] = static_cast(size); +#if PRINT_RESULTS + Result actual; + targets &= InstructionSets::Run(key, in, size, &actual); + Print(actual); +#else + const Result* expected = &known_good[size]; + targets &= InstructionSets::RunAll(key, in, size, expected, + &OnFailure); +#endif + } + return targets; +} + +// Cat + +void OnCatFailure(const char* target_name, const size_t size) { + printf("Cat mismatch at size %zu\n", size); +#ifdef HH_GOOGLETEST + EXPECT_TRUE(false); +#endif + exit(1); +} + +// Returns which targets were run/verified. +template +TargetBits VerifyCat(ThreadPool* pool) { + // Reversed order vs prior test. + const HHKey key = {0x1F1E1D1C1B1A1918ULL, 0x1716151413121110ULL, + 0x0F0E0D0C0B0A0908ULL, 0x0706050403020100ULL}; + + const size_t kMaxSize = 3 * 35; + char flat[kMaxSize]; + srand(129); + for (size_t size = 0; size < kMaxSize; ++size) { + flat[size] = static_cast(rand() & 0xFF); + } + + std::atomic targets{~0U}; + + pool->Run(0, kMaxSize, [&key, &flat, &targets](const uint32_t i) { + Result dummy; + targets.fetch_and(InstructionSets::RunAll( + key, flat, i, &dummy, &OnCatFailure)); + }); + return targets.load(); +} + +// WARNING: HighwayHash is frozen, so the golden values must not change. +const HHResult64 kExpected64[kMaxSize + 1] = { + 0x907A56DE22C26E53ull, 0x7EAB43AAC7CDDD78ull, 0xB8D0569AB0B53D62ull, + 0x5C6BEFAB8A463D80ull, 0xF205A46893007EDAull, 0x2B8A1668E4A94541ull, + 0xBD4CCC325BEFCA6Full, 0x4D02AE1738F59482ull, 0xE1205108E55F3171ull, + 0x32D2644EC77A1584ull, 0xF6E10ACDB103A90Bull, 0xC3BBF4615B415C15ull, + 0x243CC2040063FA9Cull, 0xA89A58CE65E641FFull, 0x24B031A348455A23ull, + 0x40793F86A449F33Bull, 0xCFAB3489F97EB832ull, 0x19FE67D2C8C5C0E2ull, + 0x04DD90A69C565CC2ull, 0x75D9518E2371C504ull, 0x38AD9B1141D3DD16ull, + 0x0264432CCD8A70E0ull, 0xA9DB5A6288683390ull, 0xD7B05492003F028Cull, + 0x205F615AEA59E51Eull, 0xEEE0C89621052884ull, 0x1BFC1A93A7284F4Full, + 0x512175B5B70DA91Dull, 0xF71F8976A0A2C639ull, 0xAE093FEF1F84E3E7ull, + 0x22CA92B01161860Full, 0x9FC7007CCF035A68ull, 0xA0C964D9ECD580FCull, + 0x2C90F73CA03181FCull, 0x185CF84E5691EB9Eull, 0x4FC1F5EF2752AA9Bull, + 0xF5B7391A5E0A33EBull, 0xB9B84B83B4E96C9Cull, 0x5E42FE712A5CD9B4ull, + 0xA150F2F90C3F97DCull, 0x7FA522D75E2D637Dull, 0x181AD0CC0DFFD32Bull, + 0x3889ED981E854028ull, 0xFB4297E8C586EE2Dull, 0x6D064A45BB28059Cull, + 0x90563609B3EC860Cull, 0x7AA4FCE94097C666ull, 0x1326BAC06B911E08ull, + 0xB926168D2B154F34ull, 0x9919848945B1948Dull, 0xA2A98FC534825EBEull, + 0xE9809095213EF0B6ull, 0x582E5483707BC0E9ull, 0x086E9414A88A6AF5ull, + 0xEE86B98D20F6743Dull, 0xF89B7FF609B1C0A7ull, 0x4C7D9CC19E22C3E8ull, + 0x9A97005024562A6Full, 0x5DD41CF423E6EBEFull, 0xDF13609C0468E227ull, + 0x6E0DA4F64188155Aull, 0xB755BA4B50D7D4A1ull, 0x887A3484647479BDull, + 0xAB8EEBE9BF2139A0ull, 0x75542C5D4CD2A6FFull}; + +// WARNING: HighwayHash is frozen, so the golden values must not change. +const HHResult128 kExpected128[kMaxSize + 1] = { + {0x0FED268F9D8FFEC7ull, 0x33565E767F093E6Full}, + {0xD6B0A8893681E7A8ull, 0xDC291DF9EB9CDCB4ull}, + {0x3D15AD265A16DA04ull, 0x78085638DC32E868ull}, + {0x0607621B295F0BEBull, 0xBFE69A0FD9CEDD79ull}, + {0x26399EB46DACE49Eull, 0x2E922AD039319208ull}, + {0x3250BDC386D12ED8ull, 0x193810906C63C23Aull}, + {0x6F476AB3CB896547ull, 0x7CDE576F37ED1019ull}, + {0x2A401FCA697171B4ull, 0xBE1F03FF9F02796Cull}, + {0xA1E96D84280552E8ull, 0x695CF1C63BEC0AC2ull}, + {0x142A2102F31E63B2ull, 0x1A85B98C5B5000CCull}, + {0x51A1B70E26B6BC5Bull, 0x929E1F3B2DA45559ull}, + {0x88990362059A415Bull, 0xBED21F22C47B7D13ull}, + {0xCD1F1F5F1CAF9566ull, 0xA818BA8CE0F9C8D4ull}, + {0xA225564112FE6157ull, 0xB2E94C78B8DDB848ull}, + {0xBD492FEBD1CC0919ull, 0xCECD1DBC025641A2ull}, + {0x142237A52BC4AF54ull, 0xE0796C0B6E26BCD7ull}, + {0x414460FFD5A401ADull, 0x029EA3D5019F18C8ull}, + {0xC52A4B96C51C9962ull, 0xECB878B1169B5EA0ull}, + {0xD940CA8F11FBEACEull, 0xF93A46D616F8D531ull}, + {0x8AC49D0AE5C0CBF5ull, 0x3FFDBF8DF51D7C93ull}, + {0xAC6D279B852D00A8ull, 0x7DCD3A6BA5EBAA46ull}, + {0xF11621BD93F08A56ull, 0x3173C398163DD9D5ull}, + {0x0C4CE250F68CF89Full, 0xB3123CDA411898EDull}, + {0x15AB97ED3D9A51CEull, 0x7CE274479169080Eull}, + {0xCD001E198D4845B8ull, 0xD0D9D98BD8AA2D77ull}, + {0x34F3D617A0493D79ull, 0x7DD304F6397F7E16ull}, + {0x5CB56890A9F4C6B6ull, 0x130829166567304Full}, + {0x30DA6F8B245BD1C0ull, 0x6F828B7E3FD9748Cull}, + {0xE0580349204C12C0ull, 0x93F6DA0CAC5F441Cull}, + {0xF648731BA5073045ull, 0x5FB897114FB65976ull}, + {0x024F8354738A5206ull, 0x509A4918EB7E0991ull}, + {0x06E7B465E8A57C29ull, 0x52415E3A07F5D446ull}, + {0x1984DF66C1434AAAull, 0x16FC1958F9B3E4B9ull}, + {0x111678AFE0C6C36Cull, 0xF958B59DE5A2849Dull}, + {0x773FBC8440FB0490ull, 0xC96ED5D243658536ull}, + {0x91E3DC710BB6C941ull, 0xEA336A0BC1EEACE9ull}, + {0x25CFE3815D7AD9D4ull, 0xF2E94F8C828FC59Eull}, + {0xB9FB38B83CC288F2ull, 0x7479C4C8F850EC04ull}, + {0x1D85D5C525982B8Cull, 0x6E26B1C16F48DBF4ull}, + {0x8A4E55BD6060BDE7ull, 0x2134D599058B3FD0ull}, + {0x2A958FF994778F36ull, 0xE8052D1AE61D6423ull}, + {0x89233AE6BE453233ull, 0x3ACF9C87D7E8C0B9ull}, + {0x4458F5E27EA9C8D5ull, 0x418FB49BCA2A5140ull}, + {0x090301837ED12A68ull, 0x1017F69633C861E6ull}, + {0x330DD84704D49590ull, 0x339DF1AD3A4BA6E4ull}, + {0x569363A663F2C576ull, 0x363B3D95E3C95EF6ull}, + {0xACC8D08586B90737ull, 0x2BA0E8087D4E28E9ull}, + {0x39C27A27C86D9520ull, 0x8DB620A45160932Eull}, + {0x8E6A4AEB671A072Dull, 0x6ED3561A10E47EE6ull}, + {0x0011D765B1BEC74Aull, 0xD80E6E656EDE842Eull}, + {0x2515D62B936AC64Cull, 0xCE088794D7088A7Dull}, + {0x91621552C16E23AFull, 0x264F0094EB23CCEFull}, + {0x1E21880D97263480ull, 0xD8654807D3A31086ull}, + {0x39D76AAF097F432Dull, 0xA517E1E09D074739ull}, + {0x0F17A4F337C65A14ull, 0x2F51215F69F976D4ull}, + {0xA0FB5CDA12895E44ull, 0x568C3DC4D1F13CD1ull}, + {0x93C8FC00D89C46CEull, 0xBAD5DA947E330E69ull}, + {0x817C07501D1A5694ull, 0x584D6EE72CBFAC2Bull}, + {0x91D668AF73F053BFull, 0xF98E647683C1E0EDull}, + {0x5281E1EF6B3CCF8Bull, 0xBC4CC3DF166083D8ull}, + {0xAAD61B6DBEAAEEB9ull, 0xFF969D000C16787Bull}, + {0x4325D84FC0475879ull, 0x14B919BD905F1C2Dull}, + {0x79A176D1AA6BA6D1ull, 0xF1F720C5A53A2B86ull}, + {0x74BD7018022F3EF0ull, 0x3AEA94A8AD5F4BCBull}, + {0x98BB1F7198D4C4F2ull, 0xE0BC0571DE918FC8ull}}; + +// WARNING: HighwayHash is frozen, so the golden values must not change. +const HHResult256 kExpected256[kMaxSize + 1] = { + {0xDD44482AC2C874F5ull, 0xD946017313C7351Full, 0xB3AEBECCB98714FFull, + 0x41DA233145751DF4ull}, + {0xEDB941BCE45F8254ull, 0xE20D44EF3DCAC60Full, 0x72651B9BCB324A47ull, + 0x2073624CB275E484ull}, + {0x3FDFF9DF24AFE454ull, 0x11C4BF1A1B0AE873ull, 0x115169CC6922597Aull, + 0x1208F6590D33B42Cull}, + {0x480AA0D70DD1D95Cull, 0x89225E7C6911D1D0ull, 0x8EA8426B8BBB865Aull, + 0xE23DFBC390E1C722ull}, + {0xC9CFC497212BE4DCull, 0xA85F9DF6AFD2929Bull, 0x1FDA9F211DF4109Eull, + 0x07E4277A374D4F9Bull}, + {0xB4B4F566A4DC85B3ull, 0xBF4B63BA5E460142ull, 0x15F48E68CDDC1DE3ull, + 0x0F74587D388085C6ull}, + {0x6445C70A86ADB9B4ull, 0xA99CFB2784B4CEB6ull, 0xDAE29D40A0B2DB13ull, + 0xB6526DF29A9D1170ull}, + {0xD666B1A00987AD81ull, 0xA4F1F838EB8C6D37ull, 0xE9226E07D463E030ull, + 0x5754D67D062C526Cull}, + {0xF1B905B0ED768BC0ull, 0xE6976FF3FCFF3A45ull, 0x4FBE518DD9D09778ull, + 0xD9A0AFEB371E0D33ull}, + {0x80D8E4D70D3C2981ull, 0xF10FBBD16424F1A1ull, 0xCF5C2DBE9D3F0CD1ull, + 0xC0BFE8F701B673F2ull}, + {0xADE48C50E5A262BEull, 0x8E9492B1FDFE38E0ull, 0x0784B74B2FE9B838ull, + 0x0E41D574DB656DCDull}, + {0xA1BE77B9531807CFull, 0xBA97A7DE6A1A9738ull, 0xAF274CEF9C8E261Full, + 0x3E39B935C74CE8E8ull}, + {0x15AD3802E3405857ull, 0x9D11CBDC39E853A0ull, 0x23EA3E993C31B225ull, + 0x6CD9E9E3CAF4212Eull}, + {0x01C96F5EB1D77C36ull, 0xA367F9C1531F95A6ull, 0x1F94A3427CDADCB8ull, + 0x97F1000ABF3BD5D3ull}, + {0x0815E91EEEFF8E41ull, 0x0E0C28FA6E21DF5Dull, 0x4EAD8E62ED095374ull, + 0x3FFD01DA1C9D73E6ull}, + {0xC11905707842602Eull, 0x62C3DB018501B146ull, 0x85F5AD17FA3406C1ull, + 0xC884F87BD4FEC347ull}, + {0xF51AD989A1B6CD1Full, 0xF7F075D62A627BD9ull, 0x7E01D5F579F28A06ull, + 0x1AD415C16A174D9Full}, + {0x19F4CFA82CA4068Eull, 0x3B9D4ABD3A9275B9ull, 0x8000B0DDE9C010C6ull, + 0x8884D50949215613ull}, + {0x126D6C7F81AB9F5Dull, 0x4EDAA3C5097716EEull, 0xAF121573A7DD3E49ull, + 0x9001AC85AA80C32Dull}, + {0x06AABEF9149155FAull, 0xDF864F4144E71C3Dull, 0xFDBABCE860BC64DAull, + 0xDE2BA54792491CB6ull}, + {0xADFC6B4035079FDBull, 0xA087B7328E486E65ull, 0x46D1A9935A4623EAull, + 0xE3895C440D3CEE44ull}, + {0xB5F9D31DEEA3B3DFull, 0x8F3024E20A06E133ull, 0xF24C38C8288FE120ull, + 0x703F1DCF9BD69749ull}, + {0x2B3C0B854794EFE3ull, 0x1C5D3F969BDACEA0ull, 0x81F16AAFA563AC2Eull, + 0x23441C5A79D03075ull}, + {0x418AF8C793FD3762ull, 0xBC6B8E9461D7F924ull, 0x776FF26A2A1A9E78ull, + 0x3AA0B7BFD417CA6Eull}, + {0xCD03EA2AD255A3C1ull, 0x0185FEE5B59C1B2Aull, 0xD1F438D44F9773E4ull, + 0xBE69DD67F83B76E4ull}, + {0xF951A8873887A0FBull, 0x2C7B31D2A548E0AEull, 0x44803838B6186EFAull, + 0xA3C78EC7BE219F72ull}, + {0x958FF151EA0D8C08ull, 0x4B7E8997B4F63488ull, 0xC78E074351C5386Dull, + 0xD95577556F20EEFAull}, + {0x29A917807FB05406ull, 0x3318F884351F578Cull, 0xDD24EA6EF6F6A7FAull, + 0xE74393465E97AEFFull}, + {0x98240880935E6CCBull, 0x1FD0D271B09F97DAull, 0x56E786472700B183ull, + 0x291649F99F747817ull}, + {0x1BD4954F7054C556ull, 0xFFDB2EFF7C596CEBull, 0x7C6AC69A1BAB6B5Bull, + 0x0F037670537FC153ull}, + {0x8825E38897597498ull, 0x647CF6EBAF6332C1ull, 0x552BD903DC28C917ull, + 0x72D7632C00BFC5ABull}, + {0x6880E276601A644Dull, 0xB3728B20B10FB7DAull, 0xD0BD12060610D16Eull, + 0x8AEF14EF33452EF2ull}, + {0xBCE38C9039A1C3FEull, 0x42D56326A3C11289ull, 0xE35595F764FCAEA9ull, + 0xC9B03C6BC9475A99ull}, + {0xF60115CBF034A6E5ull, 0x6C36EA75BFCE46D0ull, 0x3B17C8D382725990ull, + 0x7EDAA2ED11007A35ull}, + {0x1326E959EDF9DEA2ull, 0xC4776801739F720Cull, 0x5169500FD762F62Full, + 0x8A0DD0D90A2529ABull}, + {0x935149D503D442D4ull, 0xFF6BB41302DAD144ull, 0x339CB012CD9D36ECull, + 0xE61D53619ECC2230ull}, + {0x528BC888AA50B696ull, 0xB8AEECA36084E1FCull, 0xA158151EC0243476ull, + 0x02C14AAD097CEC44ull}, + {0xBED688A72217C327ull, 0x1EE65114F760873Full, 0x3F5C26B37D3002A6ull, + 0xDDF2E895631597B9ull}, + {0xE7DB21CF2B0B51ADull, 0xFAFC6324F4B0AB6Cull, 0xB0857244C22D9C5Bull, + 0xF0AD888D1E05849Cull}, + {0x05519793CD4DCB00ull, 0x3C594A3163067DEBull, 0xAC75081ACF119E34ull, + 0x5AC86297805CB094ull}, + {0x09228D8C22B5779Eull, 0x19644DB2516B7E84ull, 0x2B92C8ABF83141A0ull, + 0x7F785AD725E19391ull}, + {0x59C42E5D46D0A74Bull, 0x5EA53C65CA036064ull, 0x48A9916BB635AEB4ull, + 0xBAE6DF143F54E9D4ull}, + {0x5EB623696D03D0E3ull, 0xD53D78BCB41DA092ull, 0xFE2348DC52F6B10Dull, + 0x64802457632C8C11ull}, + {0x43B61BB2C4B85481ull, 0xC6318C25717E80A1ull, 0x8C4A7F4D6F9C687Dull, + 0xBD0217E035401D7Cull}, + {0x7F51CA5743824C37ull, 0xB04C4D5EB11D703Aull, 0x4D511E1ECBF6F369ull, + 0xD66775EA215456E2ull}, + {0x39B409EEF87E45CCull, 0x52B8E8C459FC79B3ull, 0x44920918D1858C24ull, + 0x80F07B645EEE0149ull}, + {0xCE8694D1BE9AD514ull, 0xBFA19026526836E7ull, 0x1EA4FDF6E4902A7Dull, + 0x380C4458D696E1FEull}, + {0xD189E18BF823A0A4ull, 0x1F3B353BE501A7D7ull, 0xA24F77B4E02E2884ull, + 0x7E94646F74F9180Cull}, + {0xAFF8C635D325EC48ull, 0x2C2E0AA414038D0Bull, 0x4ED37F611A447467ull, + 0x39EC38E33B501489ull}, + {0x2A2BFDAD5F83F197ull, 0x013D3E6EBEF274CCull, 0xE1563C0477726155ull, + 0xF15A8A5DE932037Eull}, + {0xD5D1F91EC8126332ull, 0x10110B9BF9B1FF11ull, 0xA175AB26541C6032ull, + 0x87BADC5728701552ull}, + {0xC7B5A92CD8082884ull, 0xDDA62AB61B2EEEFBull, 0x8F9882ECFEAE732Full, + 0x6B38BD5CC01F4FFBull}, + {0xCF6EF275733D32F0ull, 0xA3F0822DA2BF7D8Bull, 0x304E7435F512406Aull, + 0x0B28E3EFEBB3172Dull}, + {0xE698F80701B2E9DBull, 0x66AE2A819A8A8828ull, 0x14EA9024C9B8F2C9ull, + 0xA7416170523EB5A4ull}, + {0x3A917E87E307EDB7ull, 0x17B4DEDAE34452C1ull, 0xF689F162E711CC70ull, + 0x29CE6BFE789CDD0Eull}, + {0x0EFF3AD8CB155D8Eull, 0x47CD9EAD4C0844A2ull, 0x46C8E40EE6FE21EBull, + 0xDEF3C25DF0340A51ull}, + {0x03FD86E62B82D04Dull, 0x32AB0D600717136Dull, 0x682B0E832B857A89ull, + 0x138CE3F1443739B1ull}, + {0x2F77C754C4D7F902ull, 0x1053E0A9D9ADBFEAull, 0x58E66368544AE70Aull, + 0xC48A829C72DD83CAull}, + {0xF900EB19E466A09Full, 0x31BE9E01A8C7D314ull, 0x3AFEC6B8CA08F471ull, + 0xB8C0EB0F87FFE7FBull}, + {0xDB277D8FBE3C8EFBull, 0x53CE6877E11AA57Bull, 0x719C94D20D9A7E7Dull, + 0xB345B56392453CC9ull}, + {0x37639C3BDBA4F2C9ull, 0x6095E7B336466DC8ull, 0x3A8049791E65B88Aull, + 0x82C988CDE5927CD5ull}, + {0x6B1FB1A714234AE4ull, 0x20562E255BA6467Eull, 0x3E2B892D40F3D675ull, + 0xF40CE3FBE41ED768ull}, + {0x8EE11CB1B287C92Aull, 0x8FC2AAEFF63D266Dull, 0x66643487E6EB9F03ull, + 0x578AA91DE8D56873ull}, + {0xF5B1F8266A3AEB67ull, 0x83B040BE4DEC1ADDull, 0x7FE1C8635B26FBAEull, + 0xF4A3A447DEFED79Full}, + {0x90D8E6FF6AC12475ull, 0x1A422A196EDAC1F2ull, 0x9E3765FE1F8EB002ull, + 0xC1BDD7C4C351CFBEull}}; + +void RunTests() { + // TODO(janwas): detect number of cores. + ThreadPool pool(4); + + TargetBits tested = ~0U; + tested &= VerifyImplementations(kExpected64); + tested &= VerifyImplementations(kExpected128); + tested &= VerifyImplementations(kExpected256); + // Any failure causes immediate exit, so apparently all succeeded. + HH_TARGET_NAME::ForeachTarget(tested, [](const TargetBits target) { + printf("%10s: OK\n", TargetName(target)); + }); + + tested = ~0U; + tested &= VerifyCat(&pool); + tested &= VerifyCat(&pool); + tested &= VerifyCat(&pool); + HH_TARGET_NAME::ForeachTarget(tested, [](const TargetBits target) { + printf("%10sCat: OK\n", TargetName(target)); + }); +} + +#ifdef HH_GOOGLETEST +TEST(HighwayhashTest, OutputMatchesExpectations) { RunTests(); } +#endif + +} // namespace +} // namespace highwayhash + +#ifndef HH_GOOGLETEST +int main(int argc, char* argv[]) { + highwayhash::RunTests(); + return 0; +} +#endif diff --git a/src/Native/libdero/include/highwayhash/highwayhash_test_avx2.cc b/src/Native/libdero/include/highwayhash/highwayhash_test_avx2.cc new file mode 100644 index 0000000000..d6bf7a01a7 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/highwayhash_test_avx2.cc @@ -0,0 +1,19 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +// WARNING: this is a "restricted" source file; avoid including any headers +// unless they are also restricted. See arch_specific.h for details. + +#define HH_TARGET_NAME AVX2 +#include "highwayhash_test_target.cc" diff --git a/src/Native/libdero/include/highwayhash/highwayhash_test_neon.cc b/src/Native/libdero/include/highwayhash/highwayhash_test_neon.cc new file mode 100644 index 0000000000..f29d1585b9 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/highwayhash_test_neon.cc @@ -0,0 +1,22 @@ +// Copyright 2017-2019 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +// WARNING: this is a "restricted" source file; avoid including any headers +// unless they are also restricted. See arch_specific.h for details. + +#define HH_TARGET_NAME NEON +// GCC 4.5.4 only defines the former; 5.4 defines both. +#if defined(__ARM_NEON__) || defined(__ARM_NEON) +#include "highwayhash_test_target.cc" +#endif diff --git a/src/Native/libdero/include/highwayhash/highwayhash_test_portable.cc b/src/Native/libdero/include/highwayhash/highwayhash_test_portable.cc new file mode 100644 index 0000000000..3e6f423ef6 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/highwayhash_test_portable.cc @@ -0,0 +1,19 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +// WARNING: this is a "restricted" source file; avoid including any headers +// unless they are also restricted. See arch_specific.h for details. + +#define HH_TARGET_NAME Portable +#include "highwayhash_test_target.cc" diff --git a/src/Native/libdero/include/highwayhash/highwayhash_test_sse41.cc b/src/Native/libdero/include/highwayhash/highwayhash_test_sse41.cc new file mode 100644 index 0000000000..92c3c6fb31 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/highwayhash_test_sse41.cc @@ -0,0 +1,19 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +// WARNING: this is a "restricted" source file; avoid including any headers +// unless they are also restricted. See arch_specific.h for details. + +#define HH_TARGET_NAME SSE41 +#include "highwayhash_test_target.cc" diff --git a/src/Native/libdero/include/highwayhash/highwayhash_test_target.cc b/src/Native/libdero/include/highwayhash/highwayhash_test_target.cc new file mode 100644 index 0000000000..0b459e19f2 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/highwayhash_test_target.cc @@ -0,0 +1,220 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +// WARNING: this is a "restricted" source file; avoid including any headers +// unless they are also restricted. See arch_specific.h for details. + +#include "highwayhash_test_target.h" + +#include "highwayhash.h" + +#ifndef HH_DISABLE_TARGET_SPECIFIC +namespace highwayhash { +namespace { + +void NotifyIfUnequal(const size_t size, const HHResult64& expected, + const HHResult64& actual, const HHNotify notify) { + if (expected != actual) { + (*notify)(TargetName(HH_TARGET), size); + } +} + +// Overload for HHResult128 or HHResult256 (arrays). +template +void NotifyIfUnequal(const size_t size, const uint64_t (&expected)[kNumLanes], + const uint64_t (&actual)[kNumLanes], + const HHNotify notify) { + for (size_t i = 0; i < kNumLanes; ++i) { + if (expected[i] != actual[i]) { + (*notify)(TargetName(HH_TARGET), size); + return; + } + } +} + +// Shared logic for all HighwayHashTest::operator() overloads. +template +void TestHighwayHash(HHStateT* HH_RESTRICT state, + const char* HH_RESTRICT bytes, const size_t size, + const Result* expected, const HHNotify notify) { + // TODO(janwas): investigate (length=33) +#if HH_TARGET == HH_TARGET_Portable && HH_GCC_VERSION && !HH_CLANG_VERSION + return; +#endif + Result actual; + HighwayHashT(state, bytes, size, &actual); + NotifyIfUnequal(size, *expected, actual, notify); +} + +// Shared logic for all HighwayHashCatTest::operator() overloads. +template +void TestHighwayHashCat(const HHKey& key, const char* HH_RESTRICT bytes, + const size_t size, const Result* expected, + const HHNotify notify) { + // TODO(janwas): investigate (length=33) +#if HH_TARGET == HH_TARGET_Portable && HH_GCC_VERSION && !HH_CLANG_VERSION + return; +#endif + + // Slightly faster to compute the expected prefix hashes only once. + // Use new instead of vector to avoid headers with inline functions. + Result* results = new Result[size + 1]; + for (size_t i = 0; i <= size; ++i) { + HHStateT state_flat(key); + HighwayHashT(&state_flat, bytes, i, &results[i]); + } + + // Splitting into three fragments/Append should cover all codepaths. + const size_t max_fragment_size = size / 3; + for (size_t size1 = 0; size1 < max_fragment_size; ++size1) { + for (size_t size2 = 0; size2 < max_fragment_size; ++size2) { + for (size_t size3 = 0; size3 < max_fragment_size; ++size3) { + HighwayHashCatT cat(key); + const char* pos = bytes; + cat.Append(pos, size1); + pos += size1; + cat.Append(pos, size2); + pos += size2; + cat.Append(pos, size3); + pos += size3; + + Result result_cat; + cat.Finalize(&result_cat); + + const size_t total_size = pos - bytes; + NotifyIfUnequal(total_size, results[total_size], result_cat, notify); + } + } + } + + delete[] results; +} + +} // namespace + +template +void HighwayHashTest::operator()(const HHKey& key, + const char* HH_RESTRICT bytes, + const size_t size, + const HHResult64* expected, + const HHNotify notify) const { + HHStateT state(key); + TestHighwayHash(&state, bytes, size, expected, notify); +} + +template +void HighwayHashTest::operator()(const HHKey& key, + const char* HH_RESTRICT bytes, + const size_t size, + const HHResult128* expected, + const HHNotify notify) const { + HHStateT state(key); + TestHighwayHash(&state, bytes, size, expected, notify); +} + +template +void HighwayHashTest::operator()(const HHKey& key, + const char* HH_RESTRICT bytes, + const size_t size, + const HHResult256* expected, + const HHNotify notify) const { + HHStateT state(key); + TestHighwayHash(&state, bytes, size, expected, notify); +} + +template +void HighwayHashCatTest::operator()(const HHKey& key, + const char* HH_RESTRICT bytes, + const uint64_t size, + const HHResult64* expected, + const HHNotify notify) const { + TestHighwayHashCat(key, bytes, size, expected, notify); +} + +template +void HighwayHashCatTest::operator()(const HHKey& key, + const char* HH_RESTRICT bytes, + const uint64_t size, + const HHResult128* expected, + const HHNotify notify) const { + TestHighwayHashCat(key, bytes, size, expected, notify); +} + +template +void HighwayHashCatTest::operator()(const HHKey& key, + const char* HH_RESTRICT bytes, + const uint64_t size, + const HHResult256* expected, + const HHNotify notify) const { + TestHighwayHashCat(key, bytes, size, expected, notify); +} + +// Instantiate for the current target. +template struct HighwayHashTest; +template struct HighwayHashCatTest; + +//----------------------------------------------------------------------------- +// benchmark + +namespace { + +template +uint64_t RunHighway(const void*, const size_t size) { + HH_ALIGNAS(32) static const HHKey key = {0, 1, 2, 3}; + char in[kMaxBenchmarkInputSize]; + in[0] = static_cast(size & 0xFF); + HHResult64 result; + HHStateT state(key); + HighwayHashT(&state, in, size, &result); + return result; +} + +template +uint64_t RunHighwayCat(const void*, const size_t size) { + HH_ALIGNAS(32) static const HHKey key = {0, 1, 2, 3}; + HH_ALIGNAS(64) HighwayHashCatT cat(key); + char in[kMaxBenchmarkInputSize]; + in[0] = static_cast(size & 0xFF); + const size_t half_size = size / 2; + cat.Append(in, half_size); + cat.Append(in + half_size, size - half_size); + HHResult64 result; + cat.Finalize(&result); + return result; +} + +} // namespace + +template +void HighwayHashBenchmark::operator()(DurationsForInputs* input_map, + NotifyBenchmark notify, + void* context) const { + MeasureDurations(&RunHighway, input_map); + notify("HighwayHash", TargetName(Target), input_map, context); +} + +template +void HighwayHashCatBenchmark::operator()(DurationsForInputs* input_map, + NotifyBenchmark notify, + void* context) const { + MeasureDurations(&RunHighwayCat, input_map); + notify("HighwayHashCat", TargetName(Target), input_map, context); +} + +// Instantiate for the current target. +template struct HighwayHashBenchmark; +template struct HighwayHashCatBenchmark; + +} // namespace highwayhash +#endif // HH_DISABLE_TARGET_SPECIFIC diff --git a/src/Native/libdero/include/highwayhash/highwayhash_test_target.h b/src/Native/libdero/include/highwayhash/highwayhash_test_target.h new file mode 100644 index 0000000000..96df7337f3 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/highwayhash_test_target.h @@ -0,0 +1,90 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_HIGHWAYHASH_TEST_TARGET_H_ +#define HIGHWAYHASH_HIGHWAYHASH_TEST_TARGET_H_ + +// Tests called by InstructionSets::RunAll, so we can verify all +// implementations supported by the current CPU. + +// WARNING: this is a "restricted" header because it is included from +// translation units compiled with different flags. This header and its +// dependencies must not define any function unless it is static inline and/or +// within namespace HH_TARGET_NAME. See arch_specific.h for details. + +#include + +#include "arch_specific.h" +#include "compiler_specific.h" +#include "hh_types.h" +#include "highwayhash.h" +#include "nanobenchmark.h" + +namespace highwayhash { + +// Verifies the hash result matches "expected" and calls "notify" if not. +template +struct HighwayHashTest { + void operator()(const HHKey& key, const char* HH_RESTRICT bytes, + const size_t size, const HHResult64* expected, + const HHNotify notify) const; + void operator()(const HHKey& key, const char* HH_RESTRICT bytes, + const size_t size, const HHResult128* expected, + const HHNotify notify) const; + void operator()(const HHKey& key, const char* HH_RESTRICT bytes, + const size_t size, const HHResult256* expected, + const HHNotify notify) const; +}; + +// For every possible partition of "bytes" into zero to three fragments, +// verifies HighwayHashCat returns the same result as HighwayHashT of the +// concatenated fragments, and calls "notify" if not. The value of "expected" +// is ignored; it is only used for overloading. +template +struct HighwayHashCatTest { + void operator()(const HHKey& key, const char* HH_RESTRICT bytes, + const uint64_t size, const HHResult64* expected, + const HHNotify notify) const; + void operator()(const HHKey& key, const char* HH_RESTRICT bytes, + const uint64_t size, const HHResult128* expected, + const HHNotify notify) const; + void operator()(const HHKey& key, const char* HH_RESTRICT bytes, + const uint64_t size, const HHResult256* expected, + const HHNotify notify) const; +}; + +// Called by benchmark with prefix, target_name, input_map, context. +// This function must set input_map->num_items to 0. +using NotifyBenchmark = void (*)(const char*, const char*, DurationsForInputs*, + void*); + +constexpr size_t kMaxBenchmarkInputSize = 1024; + +// Calls "notify" with benchmark results for the input sizes specified by +// "input_map" (<= kMaxBenchmarkInputSize) plus a "context" parameter. +template +struct HighwayHashBenchmark { + void operator()(DurationsForInputs* input_map, NotifyBenchmark notify, + void* context) const; +}; + +template +struct HighwayHashCatBenchmark { + void operator()(DurationsForInputs* input_map, NotifyBenchmark notify, + void* context) const; +}; + +} // namespace highwayhash + +#endif // HIGHWAYHASH_HIGHWAYHASH_TEST_TARGET_H_ diff --git a/src/Native/libdero/include/highwayhash/highwayhash_test_vsx.cc b/src/Native/libdero/include/highwayhash/highwayhash_test_vsx.cc new file mode 100644 index 0000000000..98608c55a2 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/highwayhash_test_vsx.cc @@ -0,0 +1,22 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +// WARNING: this is a "restricted" source file; avoid including any headers +// unless they are also restricted. See arch_specific.h for details. + +#define HH_TARGET_NAME VSX + +#ifdef __VSX__ +#include "highwayhash_test_target.cc" +#endif diff --git a/src/Native/libdero/include/highwayhash/iaca.h b/src/Native/libdero/include/highwayhash/iaca.h new file mode 100644 index 0000000000..b5f301ec02 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/iaca.h @@ -0,0 +1,63 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_IACA_H_ +#define HIGHWAYHASH_IACA_H_ + +// WARNING: this is a "restricted" header because it is included from +// translation units compiled with different flags. This header and its +// dependencies must not define any function unless it is static inline and/or +// within namespace HH_TARGET_NAME. See arch_specific.h for details. + +#include "compiler_specific.h" + +// IACA (Intel's Code Analyzer, go/intel-iaca) analyzes instruction latencies, +// but only for code between special markers. These functions embed such markers +// in an executable, but only for reading via IACA - they deliberately trigger +// a crash if executed to ensure they are removed in normal builds. + +// Default off; callers must `#define HH_ENABLE_IACA 1` before including this. +#ifndef HH_ENABLE_IACA +#define HH_ENABLE_IACA 0 +#endif + +namespace highwayhash { + +#if HH_ENABLE_IACA && (HH_GCC_VERSION || HH_CLANG_VERSION) + +// Call before the region of interest. Fences hopefully prevent reordering. +static HH_INLINE void BeginIACA() { + HH_COMPILER_FENCE; + asm volatile( + ".byte 0x0F, 0x0B\n\t" // UD2 + "movl $111, %ebx\n\t" + ".byte 0x64, 0x67, 0x90\n\t"); + HH_COMPILER_FENCE; +} + +// Call after the region of interest. Fences hopefully prevent reordering. +static HH_INLINE void EndIACA() { + HH_COMPILER_FENCE; + asm volatile( + "movl $222, %ebx\n\t" + ".byte 0x64, 0x67, 0x90\n\t" + ".byte 0x0F, 0x0B\n\t"); // UD2 + HH_COMPILER_FENCE; +} + +#endif + +} // namespace highwayhash + +#endif // HIGHWAYHASH_IACA_H_ diff --git a/src/Native/libdero/include/highwayhash/instruction_sets.cc b/src/Native/libdero/include/highwayhash/instruction_sets.cc new file mode 100644 index 0000000000..a75f4d2f74 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/instruction_sets.cc @@ -0,0 +1,141 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 "instruction_sets.h" +#include "arch_specific.h" + +// Currently there are only specialized targets for X64; other architectures +// only use HH_TARGET_Portable, in which case Supported() just returns that. +#if HH_ARCH_X64 + +#include + +namespace highwayhash { + +namespace { + +bool IsBitSet(const uint32_t reg, const int index) { + return (reg & (1U << index)) != 0; +} + +// Returns the lower 32 bits of extended control register 0. +// Requires CPU support for "OSXSAVE" (see below). +uint32_t ReadXCR0() { +#if HH_MSC_VERSION + return static_cast(_xgetbv(0)); +#else + uint32_t xcr0, xcr0_high; + const uint32_t index = 0; + asm volatile(".byte 0x0F, 0x01, 0xD0" + : "=a"(xcr0), "=d"(xcr0_high) + : "c"(index)); + return xcr0; +#endif +} + +// 0 iff not yet initialized by Supported(). +// Not function-local => no compiler-generated locking. +std::atomic supported_{0}; + +// Bits indicating which instruction set extensions are supported. +enum { + kBitSSE = 1 << 0, + kBitSSE2 = 1 << 1, + kBitSSE3 = 1 << 2, + kBitSSSE3 = 1 << 3, + kBitSSE41 = 1 << 4, + kBitSSE42 = 1 << 5, + kBitAVX = 1 << 6, + kBitAVX2 = 1 << 7, + kBitFMA = 1 << 8, + kBitLZCNT = 1 << 9, + kBitBMI = 1 << 10, + kBitBMI2 = 1 << 11, + + kGroupAVX2 = kBitAVX | kBitAVX2 | kBitFMA | kBitLZCNT | kBitBMI | kBitBMI2, + kGroupSSE41 = kBitSSE | kBitSSE2 | kBitSSE3 | kBitSSSE3 | kBitSSE41 +}; + +} // namespace + +TargetBits InstructionSets::Supported() { + TargetBits supported = supported_.load(std::memory_order_acquire); + // Already initialized, return that. + if (HH_LIKELY(supported)) { + return supported; + } + + uint32_t flags = 0; + uint32_t abcd[4]; + + Cpuid(0, 0, abcd); + const uint32_t max_level = abcd[0]; + + // Standard feature flags + Cpuid(1, 0, abcd); + flags |= IsBitSet(abcd[3], 25) ? kBitSSE : 0; + flags |= IsBitSet(abcd[3], 26) ? kBitSSE2 : 0; + flags |= IsBitSet(abcd[2], 0) ? kBitSSE3 : 0; + flags |= IsBitSet(abcd[2], 9) ? kBitSSSE3 : 0; + flags |= IsBitSet(abcd[2], 19) ? kBitSSE41 : 0; + flags |= IsBitSet(abcd[2], 20) ? kBitSSE42 : 0; + flags |= IsBitSet(abcd[2], 12) ? kBitFMA : 0; + flags |= IsBitSet(abcd[2], 28) ? kBitAVX : 0; + const bool has_osxsave = IsBitSet(abcd[2], 27); + + // Extended feature flags + Cpuid(0x80000001U, 0, abcd); + flags |= IsBitSet(abcd[2], 5) ? kBitLZCNT : 0; + + // Extended features + if (max_level >= 7) { + Cpuid(7, 0, abcd); + flags |= IsBitSet(abcd[1], 3) ? kBitBMI : 0; + flags |= IsBitSet(abcd[1], 5) ? kBitAVX2 : 0; + flags |= IsBitSet(abcd[1], 8) ? kBitBMI2 : 0; + } + + // Verify OS support for XSAVE, without which XMM/YMM registers are not + // preserved across context switches and are not safe to use. + if (has_osxsave) { + const uint32_t xcr0 = ReadXCR0(); + // XMM + if ((xcr0 & 2) == 0) { + flags &= ~(kBitSSE | kBitSSE2 | kBitSSE3 | kBitSSSE3 | kBitSSE41 | + kBitSSE42 | kBitAVX | kBitAVX2 | kBitFMA); + } + // YMM + if ((xcr0 & 4) == 0) { + flags &= ~(kBitAVX | kBitAVX2); + } + } + + // Also indicates "supported" has been initialized. + supported = HH_TARGET_Portable; + + // Set target bit(s) if all their group's flags are all set. + if ((flags & kGroupAVX2) == kGroupAVX2) { + supported |= HH_TARGET_AVX2; + } + if ((flags & kGroupSSE41) == kGroupSSE41) { + supported |= HH_TARGET_SSE41; + } + + supported_.store(supported, std::memory_order_release); + return supported; +} + +} // namespace highwayhash + +#endif // HH_ARCH_X64 diff --git a/src/Native/libdero/include/highwayhash/instruction_sets.h b/src/Native/libdero/include/highwayhash/instruction_sets.h new file mode 100644 index 0000000000..24cf1d1257 --- /dev/null +++ b/src/Native/libdero/include/highwayhash/instruction_sets.h @@ -0,0 +1,118 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 HIGHWAYHASH_INSTRUCTION_SETS_H_ +#define HIGHWAYHASH_INSTRUCTION_SETS_H_ + +// Calls the best specialization of a template supported by the current CPU. +// +// Usage: for each dispatch site, declare a Functor template with a 'Target' +// argument, add a source file defining its operator() and instantiating +// Functor, add a cc_library_for_targets rule for that source file, +// and call InstructionSets::Run(/*args*/). + +#include // std::forward + +#include "arch_specific.h" // HH_TARGET_* +#include "compiler_specific.h" + +namespace highwayhash { + +// Detects TargetBits and calls specializations of a user-defined functor. +class InstructionSets { + public: +// Returns bit array of HH_TARGET_* supported by the current CPU. +// The HH_TARGET_Portable bit is guaranteed to be set. +#if HH_ARCH_X64 + static TargetBits Supported(); +#elif HH_ARCH_PPC + static HH_INLINE TargetBits Supported() { + return HH_TARGET_VSX | HH_TARGET_Portable; + } +#elif HH_ARCH_NEON + static HH_INLINE TargetBits Supported() { + return HH_TARGET_NEON | HH_TARGET_Portable; + } +#else + static HH_INLINE TargetBits Supported() { return HH_TARGET_Portable; } +#endif + + // Chooses the best available "Target" for the current CPU, runs the + // corresponding Func::operator()(args) and returns that Target + // (a single bit). The overhead of dispatching is low, about 4 cycles, but + // this should only be called infrequently (e.g. hoisting it out of loops). + template